我有两张桌子
我的表格结构如下:
的UserInfo
UserId Name
1 Sandeep
2 James
3 Vishal
的ContactInfo
Id UserId Email Mobile
1 1 e1@somemail.com 111111
2 1 e2@somemail.com 222222
3 3 v1@somemail.com 010101
现在我正在寻找下面的结果
结果
UserId UserName Email1 Mobile1 Email2 Mobile2
1 Sandeep e1@somemail.com 111111 e2@somemail.com 222222
2 James NULL NULL NULL NULL
3 Vishal v1@somemail.com 010101 NULL NULL
注意: UserInfo
与ContactInfo
之间的一对多关系
任何人都可以帮助我完成它吗?非常感谢您的回复。
答案 0 :(得分:2)
你的桌子结构不是很好。例如,如果您的用户有一封电子邮件但有两个手机号码怎么办?您与哪个手机号码关联?这种关联没有意义。这些都是当前形式的数据的准确表示:
1
ID | UserId | Email | Mobile
1 | 1 | a@a.com | 111111
2 | 1 | NULL | 222222
2
ID | UserId | Email | Mobile
1 | 1 | NULL | 111111
2 | 1 | a@a.com | 222222
3
ID | UserId | Email | Mobile
1 | 1 | NULL | 111111
2 | 1 | NULL | 222222
3 | 1 | a@a.com | NULL
相反,请考虑这样的结构:
ID | UserId | Type | Mobile
1 | 1 | Mobile | 111111
2 | 1 | Mobile | 222222
3 | 1 | Email | a@a.com
还有其他改进,但我离题了。要以当前状态回答您的问题,以下查询应该有效:
SELECT U.Name,
CI1.Email as Email1,
CI1.Mobile as Mobile1,
CI2.Email as Email2,
CI2.Mobile as Mobile2
FROM UserInfo U
LEFT JOIN (
SELECT UserID,
Email,
Mobile,
ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY ID) as row
FROM ContactInfo
) CI1
ON U.UserID = CI1.UserID
AND CI1.row = 1
LEFT JOIN (
SELECT UserID,
Email,
Mobile,
ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY ID) as row
FROM ContactInfo
) CI2
ON U.UserID = CI1.UserID
AND CI1.row = 2
答案 1 :(得分:1)
如果我理解正确,并且您只想显示每个给定用户的最低ID的ContactInfo记录,我会执行以下操作:
SELECT ci.UserId, ui.Name AS UserName, ci.*
FROM UserInfo ui
INNER JOIN (
SELECT ci.UserId AS UserId, MIN(ci.Id) AS Id
FROM ContactInfo ci
GROUP BY ci.UserId
) AS q ON (q.UserId = ui.UserId)
INNER JOIN ContactInfo ci ON (ci.Id = q.Id)
编辑: 使用OVER PARTITION BY通常也可以,但我通常更喜欢使用嵌套查询,因为它们通常有更好的执行计划。
答案 2 :(得分:1)
您可以执行dynamic crosstab来实现此目标。
DECLARE @sql NVARCHAR(MAX)
SELECT @sql =
'SELECT
u.UserId
, u.Name' + CHAR(10)
SELECT @sql = @sql +
' , MAX(CASE WHEN t.rn = ' + CONVERT(VARCHAR(10), rn) +' THEN t.Email END) AS '
+ QUOTENAME('Email' + CONVERT(VARCHAR(10), rn)) + CHAR(10) +
' , MAX(CASE WHEN t.rn = ' + CONVERT(VARCHAR(10), rn) +' THEN t.Mobile END) AS '
+ QUOTENAME('Mobile' + CONVERT(VARCHAR(10), rn)) + CHAR(10)
FROM (
SELECT DISTINCT
rn = ROW_NUMBER() OVER(PARTITION BY UserId ORDER BY Id)
FROM ContactInfo
)t
-- Add filter here for ROW_NUMBER, e.g. starting from the 25th row to 50th
WHERE rn BETWEEN 25 AND 50
SELECT @sql = @sql +
'FROM UserInfo u
LEFT JOIN (
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY UserId ORDER BY Id)
FROM ContactInfo
)t
ON t.UserId = u.UserId
-- Add filter here for ROW_NUMBER, e.g. starting from the 25th row to 50th
AND rn BETWEEN 25 AND 50
GROUP BY u.UserId, u.Name
ORDER BY u.UserId, u.Name'
PRINT @sql
EXEC(@sql)