我有2个SQL表。
IF OBJECT_ID ('A', 'U') IS NOT NULL
BEGIN
DROP TABLE A;
END
GO
CREATE TABLE A
(
[ID] [INT] IDENTITY(1,1) Primary Key NOT NULL,
[Name] [NVARCHAR](80) DEFAULT('Guest'),
[Acct_Num] [NVARCHAR](255)
)
GO
IF OBJECT_ID ('B', 'U') IS NOT NULL
BEGIN
DROP TABLE B;
END
GO
CREATE TABLE B
(
[ID] [INT] IDENTITY(1,1) Primary Key NOT NULL,
[Name] [NVARCHAR](80) DEFAULT('Unk'),
[Acct_Num] [NVARCHAR](255)
)
GO
添加在测试数据
INSERT INTO [A] ([Name], [Acct_Num]) VALUES ('Test1', '5006347')
INSERT INTO [A] ([Name], [Acct_Num]) VALUES ('Test2', '5006348')
INSERT INTO [A] ([Name], [Acct_Num]) VALUES ('Test3', '5006349')
GO
INSERT INTO [B] ([Name], [Acct_Num]) VALUES ('Attach1', '5006347')
INSERT INTO [B] ([Name], [Acct_Num]) VALUES ('Attach2', '5006347')
GO
我要寻找的是返回A [名称],A [Acct_Num]和B [Name]的查询,其中A [Acct_Num]匹配B [Acct_Num]。 B [名称]必须作为附加列添加到结果中。 (样品输出下面给出)
现在我急需的是表B中唯一可能的2项,但如果它是5?
我想是这样的,但它不会在AS“列名”返回值。
DECLARE @Row_Cnt Integer = (SELECT COUNT(*) FROM [B] WHERE B.Acct_Num = '5006347')
SELECT A.[Name], A.[Acct_Num],
CASE WHEN @Row_Cnt = '1' THEN
(SELECT MIN(B.[Name]) FROM B WHERE B.Acct_Num = A.Acct_Num)
END AS 'Attach 1',
CASE WHEN @Row_Cnt = '2' THEN
(SELECT MAX(B.[Name]) FROM B WHERE B.Acct_Num = A.Acct_Num)
END AS 'Attach 2'
FROM A WHERE A.Acct_Num = '5006347'
现在这可以使用MIN和MAX进行工作,但是如果找到2个以上的项目,则无法获得所有匹配项。
SELECT A.[Name], A.[Acct_Num], MIN(B.[Name]) AS 'Attach 1', MAX(B.[Name]) AS 'Attach 2'
FROM A
JOIN B ON B.Acct_Num = A.Acct_Num
WHERE A.Acct_Num = '5006347'
GROUP BY A.Name, A.Acct_Num
结果:
Name | Acct_Num | Attach 1 | Attach 2
Test1 | 5006347 | Attach1 | Attach2
对于我的第2列任务来说,这不是一个非常出色的解决方案(尽管是功能性的),但我感觉需要更多的返回列。
因此,什么是将容纳返回的项目的一个未知量的更有效的方法。
谢谢!
答案 0 :(得分:0)
动态SQL就像您以“编程”语言连接SQL代码一样,但是您仍然只能使用SQL,例如像这样:
DECLARE @NameA NVARCHAR(80), @NameB NVARCHAR(80), @Acct_Num NVARCHAR(255),
@DynamicSQL NVARCHAR(MAX), @i INT
SET @Acct_Num = '5006347'
SET @i = 1
SELECT @NameA = [Name] FROM [A] WHERE Acct_Num = @Acct_Num
-- Start of Dynamic SQL (or dynamic SELECT) - I include columns
-- A.[Name] and Acct_Num, which I've know already
SELECT @DynamicSQL = N'SELECT N''' + @NameA + N''' AS NameA, N''' +
@Acct_Num + ''' AS Acct_Num,'
DECLARE cur CURSOR FAST_FORWARD LOCAL FOR
SELECT B.[Name]
FROM B
JOIN A ON A.Acct_Num = B.Acct_Num
WHERE A.[Name] = @NameA
OPEN cur
WHILE(1=1)
BEGIN
FETCH NEXT FROM cur INTO @NameB
IF @@FETCH_STATUS <> 0
BREAK;
-- Add each row from cursor to the dynamic sql string as a column.
-- Added columns are named 'Col' and order number (eg. Col1, Col2 etc.)
SELECT @DynamicSQL = @DynamicSQL + N'N''' + @NameB + N''' AS Col' +
CAST(@i AS NVARCHAR) + ','
SELECT @i = @i+1
END
SELECT @DynamicSQL = LEFT(@DynamicSQL, LEN(@DynamicSQL) - 1) -- remove last comma
EXEC sp_executesql @DynamicSQL
这不是经过优化的代码,但我希望可以进行演示。如果您在A表中针对一个Acct_Num有多个名称,则确实需要对代码进行一些修改。
答案 1 :(得分:0)
或者,对于Dynamic SQL,如果使用的是2017版,则可以为一列获取动态组合的输出,这要归功于新的聚合功能,该列将作为所有值的列表构建。 然后由您的代码决定如何将数据拆分为多列。
SELECT A.[Name], A.[Acct_Num], STRING_AGG(B.[Name], ',') AS Attaches
FROM A
JOIN B ON B.Acct_Num = A.Acct_Num
WHERE A.Acct_Num = '5006347'
GROUP BY A.Name, A.Acct_Num
名称Acct_Num附件 Test1 5006347 Attach1,Attach2
如果您想查看更多示例,可以在Google上搜索group_concat,它是MySQL等效的功能,已经存在很长时间了。