简体   繁体   English

如何将多个子选择的SQL压缩为更合理的东西?

[英]How do I condense this SQL of multiple sub-selects into something more sane?

The following query returns a single row, as desired. 以下查询根据需要返回单行。 The 'contracts' table has 6 fields, each with a different username in it, for which I want to retrieve first/last names from a separate 'users' table. “合同”表有6个字段,每个字段中都有不同的用户名,我想从一个单独的“用户”表中检索其名字/姓氏。 This works fine, but is there something more concise? 这可以正常工作,但还有其他更简洁的方法吗? I'm think the solution must be something using GROUP BY contracts.id to keep it one row, but I can't seem to find anything better than this slew of sub-selects. 我认为解决方案一定是使用GROUP BY Contracts.id使其保持一行的方法,但是我似乎找不到比这一系列子选择更好的方法。

Help! 救命!

SELECT contracts.field1, contracts.field2, 
(SELECT first_name FROM users WHERE username = service_provider_1),
(SELECT last_name FROM users WHERE username = service_provider_1),
(SELECT first_name FROM users WHERE username = service_provider_2),
(SELECT last_name FROM users WHERE username = service_provider_2),
(SELECT first_name FROM users WHERE username = service_org_business_contact),
(SELECT last_name FROM users WHERE username = service_org_business_contact),
(SELECT first_name FROM users WHERE username = client_service_contact_1),
(SELECT last_name FROM users WHERE username = client_service_contact_1),
(SELECT first_name FROM users WHERE username = client_service_contact_2),
(SELECT last_name FROM users WHERE username = client_service_contact_2),
(SELECT first_name FROM users WHERE username = client_business_contact),
(SELECT last_name FROM users WHERE username = client_business_contact)
FROM contracts
WHERE id = ?

It wouldn't be so bad if I could get both first/last name from a single sub-select... so even with a cruddy sub-select solution I have twice the verbosity I should think I need... 如果我可以从一个子选择中同时获得名字/姓氏,那并不会太糟糕……因此,即使采用了糟糕的子选择解决方案,我的冗长程度也应该是我认为的两倍...

EDIT: I get it now. 编辑:我现在知道了。 The answer to being able to join to the same table multiple times is to use an alias for the table. 能够多次连接到同一表的答案是为表使用别名。 Thank folks! 谢谢大家! New code is: 新代码是:

SELECT contracts.field1, contracts.field2, 
sp1.first_name, sp1.last_name, 
sp2.first_name, sp2.last_name, 
sobc.first_name, sobc.last_name, 
csc1.first_name, csc1.last_name, 
csc2.first_name, csc2.last_name, 
cbc.first_name, cbc.last_name
FROM contracts
JOIN users AS sp1 ON service_provider_1 = sp1.username
JOIN users AS sp2 ON service_provider_2 = sp2.username
JOIN users AS sobc ON service_org_business_contact = sobc.username
JOIN users AS csc1 ON client_service_contact_1 = csc1.username
JOIN users AS csc2 ON client_service_contact_2 = csc2.username
JOIN users AS cbc ON client_business_contact = cbc.username
WHERE contracts.id = ?

Sadly, using joins is almost as verbose as using the subselects, but I assume it might be faster? 可悲的是,使用联接几乎与使用子选择一样冗长,但是我认为它可能更快?

为什么不加入6次用户表?

SELECT contracts.field1, contracts.field2, 
sp1.first_name,
sp1.last_name 
sp2.first_name,
sp2.last_name,
/* etc, etc */
FROM
contracts
INNER JOIN
users sp1
ON
contracts.id = sp1.id
AND sp1.username = service_provider_1
INNER JOIN 
users sp2
ON contracts.id = sp2.id
AND sp2.username = service_provider_2
INNER JOIN 
users sobc
ON contracts.id = sobc.id
AND sobc.username = service_org_business_contact
INNER JOIN
/* etc, etc */
WHERE contracts.id = @myid

did you also want to combine first_name and last_name for each username? 您是否还想为每个用户名组合first_namelast_name You can do this like 你可以这样做

RTRIM(sp1.first_name) + ' ' + RTRIM(sp1.last_name) as sp1_name

in your SELECT clause. 在您的SELECT子句中。 The RTRIM are necessary if the data type is (N)CHAR, not necessary if the type is (N)VARCHAR 如果数据类型为(N)CHAR,则RTRIM是必需的;如果数据类型为(N)VARCHAR,则不需要RTRIM

EDIT: As stated in the comments on this answer , the JOIN on id is probably not necessary, in which case it becomes 编辑:对此答案的评论中所述,id上的JOIN可能不是必需的,在这种情况下,它变为

SELECT 
contracts.field1, 
contracts.field2, 
sp1.first_name,
sp1.last_name 
sp2.first_name,
sp2.last_name,
/* etc, etc */
FROM
contracts
INNER JOIN
users sp1
ON
sp1.username = service_provider_1
INNER JOIN 
users sp2
ON
sp2.username = service_provider_2
INNER JOIN 
users sobc
ON 
sobc.username = service_org_business_contact
INNER JOIN
/* etc, etc */
WHERE contracts.id = @myid

My layout probably makes it appear longer! 我的布局可能会使它看起来更长! You may need to use LEFT OUTER JOINS if it is possible to have a contract record that doesn't have a first_name and last_name for one of it's fields within the users table. 如果可能有一个合同记录,而该记录没有在users表中的其中一个字段具有first_namelast_name ,则可能需要使用LEFT OUTER JOINS。

select 
 c.field1,c.field2
,SP1.first_name ,SP1.last_name
,SP2.first_name ,SP2.last_name
,SOBC.first_name,SOBC.last_name
,CSC1.first_name,CSC1.last_name
,CSC2.first_name,CSC2.last_name
,CBC.first_name ,CBC.last_name
from contracts C
left join users as SP1  on SP1.Username  = C.service_provider_1 
left join users as SP2  on SP2.Username  = C.service_provider_2 
left join users as SOBC on SOBC.Username = C.service_org_business_contact 
left join users as CSC1 on SP1.Username  = C.client_service_contact_1 
left join users as CSC2 on SP1.Username  = C.client_service_contact_2 
left join users as CBC  on CBC.Username  = C.client_business_contact 

where c.ID = ?

I can't help but think that pushing the names out to a separate table along with a column for the name type might be a good idea here. 我忍不住认为将名称与名称类型的列一起推到单独的表中可能是个好主意。

Edit: Or have another join table sitting between contracts and users to do a many-to-many join properly. 编辑:或者在合同和用户之间放置另一个联接表,以正确进行多对多联接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM