SQL 服务器:Select 基于列值的不同数量的值
SQL Server: Select Varying Number Of Values Based On Column Value
版本:Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 2014 年 2 月 20 日 20:04:26 版权所有 (c) Windows NT 上的 Microsoft Corporation Express Edition(64 位) 6.1(内部版本 7601:Service Pack 1)
我需要 select 来自 table 的不同数量的值,其中特定列等于参数并且特定列是 LIKE 'String1' 或 'String2'.
我已经创建了一个存储过程,它是 returning MAX 和 MIN 字符串,但自然这个方法不是动态的。
我已经尝试了以下查询,它说它成功完成,但没有 return 任何结果。
SELECT UPC, PartNum, PartDesc
FROM dbo.table
WHERE UPC = @upc
GROUP BY UPC, PartNum, PartDesc
HAVING PartDesc in ('%RED%','%BLUE%')
ORDER BY PartDesc;
示例table:
ID UPC PartNum PartDesc
-------------------------------------------
1 123 543 Red1
2 123 345 Blue1
3 123 654 Red2
4 123 765 Blue2
我需要从应用程序将参数作为@upc 传递给存储过程。
它会在哪里找到类似于“%RED%”或“%BLUE%”的任何 PartDesc 以及 UPC = @upc。
然后将找到的 Part#(s) 存储在一个新的 table 中,以便稍后查询。
从存储过程Table创建:
ID UPC Red1 Red2 Blue1 Blue2
----------------------------------------------------------
1 123 543 654 345 765
每个 UPC 号码可以有任意数字或 "Red" 或 "Blue" 的组合。 IE。,
一些 UPC 号码可能只有两个 "Red" 部分和一个 "Blue" 部分,而其他一些可能只有两个 "Red" 部分而没有 "Blue" 部分。也许五个 "Red" 部分和十个 "Blue" 部分。
我该如何编写查询,将找到的不同数量的结果存储到存储过程中的新 table?
编辑
似乎应该使用 PIVOT 函数,但我不确定如何在我的场景中使用所需的聚合。就此而言,我不需要在 PartDesc 或任何其他列的 "SUM" 上进行调整。
也许是一个动态的枢轴?
编辑 根据 Corgi 的推荐。另外,展示我的作品。
DECLARE @upc As varchar(13)
DECLARE @Red1 As nvarchar(100) = CASE
WHEN
(
SELECT MIN(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%RED%' AND UPC = @upc
) IS NOT NULL THEN
(
SELECT MIN(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%RED%' AND UPC = @upc
)
ELSE 'Not Found'
END
DECLARE @Red2 As nvarchar(100) = CASE
WHEN
(
SELECT MAX(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%RED%' AND UPC = @upc
) IS NOT NULL THEN
(
SELECT MAX(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%RED%' AND UPC = @upc
)
ELSE 'Not Found'
END
DECLARE @Blue1 As nvarchar(100) = CASE
WHEN
(
SELECT MAX(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%BLUE%' AND UPC = @upc
) IS NOT NULL THEN
(
SELECT MAX(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%BLUE%' AND UPC = @upc
)
ELSE 'Not Found'
END
;WITH MostColumns AS
(
SELECT UPC, @Red1 As Part1, @Red2 As Part2, @Blue1 As Part3
FROM (SELECT UPC, PartNum, PartDesc
FROM dbo.table) AS source
PIVOT
(MIN(PartNum) FOR PartDesc IN ([Part1], [Part2], [Part3])) AS pvt
)
SELECT MIN(p.ID) AS ID, p.UPC, mc.Part1, mc.Part2, mc.Part3
INTO MyNewTable
FROM dbo.table p
INNER JOIN MostColumns mc ON p.UPC = mc.UPC
GROUP BY p.UPC, mc.Part1, mc.Part2, mc.Part3
结果:
ID UPC Part1 Part2 Part3
2876 123 Not Found Not Found Not Found
2758 213 Not Found Not Found Not Found
2321 312 Not Found Not Found Not Found
802 321 Not Found Not Found Not Found
868 132 Not Found Not Found Not Found
这是正确的格式,但没有雪茄。我知道一个事实,我所有的 UPC 至少包含一个 Red1
部分。由于某种原因,它没有找到任何部分。
编辑--回答
@Corgi 在对动态枢轴进行更多研究后,我得出了这个解决方案。我仍然需要在它的基础上进行构建,以使其按照我需要的方式运行。虽然,这些与这个问题无关。
感谢@bluefeet 在此 post 中的回答。
SQL Dynamic Pivot
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ','
+ QUOTENAME('Part_' + cast(rn as varchar(10)))
from dbo.table
cross apply
(
select row_number() over(partition by UPC order by PartNum) rn
from dbo.table
) x
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT UPC, ' + @cols + ' from
(
select UPC, PartNum,
''Component_''
+ cast(row_number() over(partition by UPC order by PartNum) as varchar(10)) val
from dbo.table
) x
pivot
(
max(PartNum)
for val in (' + @cols + ')
) p '
execute(@query)
您对 PIVOT
的观察是正确的,但如果不指定输出列名称(即来自 PartDesc
的值),您不能实际使用 PIVOT
。这听起来像是,因为这些 PartDesc
值的数量可能不同,所以最接近的是找到所有值:
SELECT DISTINCT t.PartDesc
FROM MyTable t
WHERE t.PartDesc LIKE '%Red%' OR t.PartDesc LIKE '%Blue%'
然后您可以使用这些值来构建您的查询。如果你真的必须让查询是动态的,你需要构造一个查询字符串来在你的动态查询中使用类似sp_executesql
. The way you would create the table from the output is by using SELECT... INTO
的东西。
您需要的 PIVOT
语法与 SELECT... INTO
相结合,可能类似于:
;WITH MostColumns AS
(
SELECT UPC, Red1, Red2, Blue1, Blue2
FROM (SELECT UPC, PartNum, PartDesc
FROM dbo.table) AS source
PIVOT
(MIN(PartNum) FOR PartDesc IN ([Red1], [Red2], [Blue1], [Blue2])) AS pvt
)
SELECT MIN(p.ID) AS ID, p.UPC, mc.Red1, mc.Red2, mc.Blue1, mc.Blue2
INTO MyNewTable
FROM dbo.table p
INNER JOIN MostColumns mc ON p.UPC = mc.UPC
GROUP BY p.UPC, mc.Red1, mc.Red2, mc.Blue1, mc.Blue2
MostColumns
常见的 table 表达式在那里,因为在您的原始查询中使用 ID
效果不佳 - 这是一个 "extra" 列不是枢轴的一部分。
版本:Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 2014 年 2 月 20 日 20:04:26 版权所有 (c) Windows NT 上的 Microsoft Corporation Express Edition(64 位) 6.1(内部版本 7601:Service Pack 1)
我需要 select 来自 table 的不同数量的值,其中特定列等于参数并且特定列是 LIKE 'String1' 或 'String2'.
我已经创建了一个存储过程,它是 returning MAX 和 MIN 字符串,但自然这个方法不是动态的。
我已经尝试了以下查询,它说它成功完成,但没有 return 任何结果。
SELECT UPC, PartNum, PartDesc
FROM dbo.table
WHERE UPC = @upc
GROUP BY UPC, PartNum, PartDesc
HAVING PartDesc in ('%RED%','%BLUE%')
ORDER BY PartDesc;
示例table:
ID UPC PartNum PartDesc
-------------------------------------------
1 123 543 Red1
2 123 345 Blue1
3 123 654 Red2
4 123 765 Blue2
我需要从应用程序将参数作为@upc 传递给存储过程。
它会在哪里找到类似于“%RED%”或“%BLUE%”的任何 PartDesc 以及 UPC = @upc。 然后将找到的 Part#(s) 存储在一个新的 table 中,以便稍后查询。
从存储过程Table创建:
ID UPC Red1 Red2 Blue1 Blue2
----------------------------------------------------------
1 123 543 654 345 765
每个 UPC 号码可以有任意数字或 "Red" 或 "Blue" 的组合。 IE。, 一些 UPC 号码可能只有两个 "Red" 部分和一个 "Blue" 部分,而其他一些可能只有两个 "Red" 部分而没有 "Blue" 部分。也许五个 "Red" 部分和十个 "Blue" 部分。
我该如何编写查询,将找到的不同数量的结果存储到存储过程中的新 table?
编辑 似乎应该使用 PIVOT 函数,但我不确定如何在我的场景中使用所需的聚合。就此而言,我不需要在 PartDesc 或任何其他列的 "SUM" 上进行调整。 也许是一个动态的枢轴?
编辑 根据 Corgi 的推荐。另外,展示我的作品。
DECLARE @upc As varchar(13)
DECLARE @Red1 As nvarchar(100) = CASE
WHEN
(
SELECT MIN(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%RED%' AND UPC = @upc
) IS NOT NULL THEN
(
SELECT MIN(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%RED%' AND UPC = @upc
)
ELSE 'Not Found'
END
DECLARE @Red2 As nvarchar(100) = CASE
WHEN
(
SELECT MAX(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%RED%' AND UPC = @upc
) IS NOT NULL THEN
(
SELECT MAX(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%RED%' AND UPC = @upc
)
ELSE 'Not Found'
END
DECLARE @Blue1 As nvarchar(100) = CASE
WHEN
(
SELECT MAX(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%BLUE%' AND UPC = @upc
) IS NOT NULL THEN
(
SELECT MAX(PartNum) FROM dbo.table
WHERE PartDesc LIKE '%BLUE%' AND UPC = @upc
)
ELSE 'Not Found'
END
;WITH MostColumns AS
(
SELECT UPC, @Red1 As Part1, @Red2 As Part2, @Blue1 As Part3
FROM (SELECT UPC, PartNum, PartDesc
FROM dbo.table) AS source
PIVOT
(MIN(PartNum) FOR PartDesc IN ([Part1], [Part2], [Part3])) AS pvt
)
SELECT MIN(p.ID) AS ID, p.UPC, mc.Part1, mc.Part2, mc.Part3
INTO MyNewTable
FROM dbo.table p
INNER JOIN MostColumns mc ON p.UPC = mc.UPC
GROUP BY p.UPC, mc.Part1, mc.Part2, mc.Part3
结果:
ID UPC Part1 Part2 Part3
2876 123 Not Found Not Found Not Found
2758 213 Not Found Not Found Not Found
2321 312 Not Found Not Found Not Found
802 321 Not Found Not Found Not Found
868 132 Not Found Not Found Not Found
这是正确的格式,但没有雪茄。我知道一个事实,我所有的 UPC 至少包含一个 Red1
部分。由于某种原因,它没有找到任何部分。
编辑--回答 @Corgi 在对动态枢轴进行更多研究后,我得出了这个解决方案。我仍然需要在它的基础上进行构建,以使其按照我需要的方式运行。虽然,这些与这个问题无关。 感谢@bluefeet 在此 post 中的回答。 SQL Dynamic Pivot
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ','
+ QUOTENAME('Part_' + cast(rn as varchar(10)))
from dbo.table
cross apply
(
select row_number() over(partition by UPC order by PartNum) rn
from dbo.table
) x
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT UPC, ' + @cols + ' from
(
select UPC, PartNum,
''Component_''
+ cast(row_number() over(partition by UPC order by PartNum) as varchar(10)) val
from dbo.table
) x
pivot
(
max(PartNum)
for val in (' + @cols + ')
) p '
execute(@query)
您对 PIVOT
的观察是正确的,但如果不指定输出列名称(即来自 PartDesc
的值),您不能实际使用 PIVOT
。这听起来像是,因为这些 PartDesc
值的数量可能不同,所以最接近的是找到所有值:
SELECT DISTINCT t.PartDesc
FROM MyTable t
WHERE t.PartDesc LIKE '%Red%' OR t.PartDesc LIKE '%Blue%'
然后您可以使用这些值来构建您的查询。如果你真的必须让查询是动态的,你需要构造一个查询字符串来在你的动态查询中使用类似sp_executesql
. The way you would create the table from the output is by using SELECT... INTO
的东西。
您需要的 PIVOT
语法与 SELECT... INTO
相结合,可能类似于:
;WITH MostColumns AS
(
SELECT UPC, Red1, Red2, Blue1, Blue2
FROM (SELECT UPC, PartNum, PartDesc
FROM dbo.table) AS source
PIVOT
(MIN(PartNum) FOR PartDesc IN ([Red1], [Red2], [Blue1], [Blue2])) AS pvt
)
SELECT MIN(p.ID) AS ID, p.UPC, mc.Red1, mc.Red2, mc.Blue1, mc.Blue2
INTO MyNewTable
FROM dbo.table p
INNER JOIN MostColumns mc ON p.UPC = mc.UPC
GROUP BY p.UPC, mc.Red1, mc.Red2, mc.Blue1, mc.Blue2
MostColumns
常见的 table 表达式在那里,因为在您的原始查询中使用 ID
效果不佳 - 这是一个 "extra" 列不是枢轴的一部分。