C# SQL Server中跨3个表的透视查询
我无法找到以下问题的解决方案: 我有三个表(MS SQL): 机器C# SQL Server中跨3个表的透视查询,c#,sql,sql-server,join,C#,Sql,Sql Server,Join,我无法找到以下问题的解决方案: 我有三个表(MS SQL): 机器 +-----------+-------------+ | MachineID | MachineName | +-----------+-------------+ | 1 | Press 1 | | 2 | Press 2 | | 3 | Press 3 | +-----------+-------------+ +-----------+------
+-----------+-------------+
| MachineID | MachineName |
+-----------+-------------+
| 1 | Press 1 |
| 2 | Press 2 |
| 3 | Press 3 |
+-----------+-------------+
+-----------+-------------+
| PartID | PartName |
+-----------+-------------+
| 1 | Part 1 |
| 2 | Part 2 |
| 3 | Part 3 |
+-----------+-------------+
零件
+-----------+-------------+
| MachineID | MachineName |
+-----------+-------------+
| 1 | Press 1 |
| 2 | Press 2 |
| 3 | Press 3 |
+-----------+-------------+
+-----------+-------------+
| PartID | PartName |
+-----------+-------------+
| 1 | Part 1 |
| 2 | Part 2 |
| 3 | Part 3 |
+-----------+-------------+
机器零件分配
+----+-----------+--------+--+
| ID | MachineId | PartID | |
+----+-----------+--------+--+
| 1 | 1 | 1 | |
| 2 | 1 | 2 | |
| 3 | 1 | 3 | |
| 4 | 2 | 2 | |
| 5 | 3 | 2 | |
| 6 | 3 | 3 | |
+----+-----------+--------+--+
这就是我想要得到的查询结果:
(如果指定了机器和零件,则在machinePartnerAssign中存在匹配行时,其值为true(或1),否则其值应为false(或0)。我还可以为每个零件/机器组合在machinePartnerAssign中插入一行,并包含额外的布尔值(位)列。我仍然需要一个类似的透视查询。(?) 所需结果(如果方便的话,可以用1和0交换true或false) 目前,我正在使用c#中的循环进行此操作:首先选择每台机器,然后选择所有零件,然后选择机器为特定机器/零件组合指定零件。如果返回>1行,则为真。这意味着对每台机器/部件进行一次查询 我相信有一种更优雅的方式。我知道MSSQL提供了PIVOT功能,但我不知道如何在我的案例中使用它
非常感谢 可能是这样的
PIVOT
DECLARE @Parts AS TABLE (PartID int, PartName varchar(30))
INSERT INTO @Parts VALUES
(1 ,'Part 1'),
(2 ,'Part 2'),
(3 ,'Part 3')
DECLARE @Machine AS TABLE( MachineID int, MachineName varchar(30))
INSERT INTO @Machine VALUES (1, 'Press 1'), (2, 'Press 2'), (3, 'Press 3')
DECLARE @MachinePartAssign AS TABLE( ID int, MachineId int, PartID int )
INSERT INTO @MachinePartAssign VALUES (1,1,1),(2,1,2),(3,1,3),(4,2,2),(5,3,2),(6,3,3)
SELECT MachineName, Isnull([Part 1],0) AS [Part 1], Isnull([Part 2],0) AS [Part 2], isnull([Part 3],0) AS [Part 3]
FROM
(
SELECT m.MachineName, p.PartName, IIF(mpa.ID IS NULL, 0, 1) AS MachinePart FROM @Machine m
LEFT JOIN @MachinePartAssign mpa ON m.MachineID = mpa.MachineId
LEFT JOIN @Parts p ON p.PartID = mpa.PartID
) src
PIVOT
(
max(MachinePart) FOR PartName IN ([Part 1], [Part 2], [Part 3] )
) pvt
CREATE TABLE #Parts (PartID int, PartName varchar(30))
INSERT INTO #Parts VALUES
(1 ,'Part 1'),
(2 ,'Part 2'),
(3 ,'Part 3'),
(4 ,'Part 4')
CREATE TABLE #Machine ( MachineID int, MachineName varchar(30))
INSERT INTO #Machine VALUES (1, 'Press 1'), (2, 'Press 2'), (3, 'Press 3')
CREATE TABLE #MachinePartAssign ( ID int, MachineId int, PartID int )
INSERT INTO #MachinePartAssign VALUES (1,1,1),(2,1,2),(3,1,3),(4,2,2),(5,3,2),(6,3,3)
DECLARE @PivotColumns nvarchar(max)
SELECT @PivotColumns = STUFF((SELECT concat(',[',p.PartName,']') FROM #Parts p FOR XML PATH ('')),1,1,'')
DECLARE @HeaderColumns nvarchar(max)
SELECT @HeaderColumns = STUFF((SELECT concat(', ISNULL([',p.PartName,'],0) AS [', p.PartName,']') FROM #Parts p FOR XML PATH ('')),1,1,'')
--SELECT @HeaderColumns, @PivotColumns
DECLARE @sql nvarchar(max) = CONCAT('
SELECT MachineName,', @HeaderColumns ,
' FROM
(
SELECT m.MachineName, p.PartName, IIF(mpa.ID IS NULL, 0, 1) AS MachinePart FROM #Machine m
LEFT JOIN #MachinePartAssign mpa ON m.MachineID = mpa.MachineId
LEFT JOIN #Parts p ON p.PartID = mpa.PartID
) src
PIVOT
(
max(MachinePart) FOR PartName IN (',@PivotColumns,')
) pvt'
)
-- PRINT @sql
EXEC(@sql)
DROP TABLE #Machine
DROP TABLE #Parts
DROP TABLE #MachinePartAssign
此查询的结果:
若表部分可以添加其他项,那个么可以像这样使用动态sql查询
DECLARE @Parts AS TABLE (PartID int, PartName varchar(30))
INSERT INTO @Parts VALUES
(1 ,'Part 1'),
(2 ,'Part 2'),
(3 ,'Part 3')
DECLARE @Machine AS TABLE( MachineID int, MachineName varchar(30))
INSERT INTO @Machine VALUES (1, 'Press 1'), (2, 'Press 2'), (3, 'Press 3')
DECLARE @MachinePartAssign AS TABLE( ID int, MachineId int, PartID int )
INSERT INTO @MachinePartAssign VALUES (1,1,1),(2,1,2),(3,1,3),(4,2,2),(5,3,2),(6,3,3)
SELECT MachineName, Isnull([Part 1],0) AS [Part 1], Isnull([Part 2],0) AS [Part 2], isnull([Part 3],0) AS [Part 3]
FROM
(
SELECT m.MachineName, p.PartName, IIF(mpa.ID IS NULL, 0, 1) AS MachinePart FROM @Machine m
LEFT JOIN @MachinePartAssign mpa ON m.MachineID = mpa.MachineId
LEFT JOIN @Parts p ON p.PartID = mpa.PartID
) src
PIVOT
(
max(MachinePart) FOR PartName IN ([Part 1], [Part 2], [Part 3] )
) pvt
CREATE TABLE #Parts (PartID int, PartName varchar(30))
INSERT INTO #Parts VALUES
(1 ,'Part 1'),
(2 ,'Part 2'),
(3 ,'Part 3'),
(4 ,'Part 4')
CREATE TABLE #Machine ( MachineID int, MachineName varchar(30))
INSERT INTO #Machine VALUES (1, 'Press 1'), (2, 'Press 2'), (3, 'Press 3')
CREATE TABLE #MachinePartAssign ( ID int, MachineId int, PartID int )
INSERT INTO #MachinePartAssign VALUES (1,1,1),(2,1,2),(3,1,3),(4,2,2),(5,3,2),(6,3,3)
DECLARE @PivotColumns nvarchar(max)
SELECT @PivotColumns = STUFF((SELECT concat(',[',p.PartName,']') FROM #Parts p FOR XML PATH ('')),1,1,'')
DECLARE @HeaderColumns nvarchar(max)
SELECT @HeaderColumns = STUFF((SELECT concat(', ISNULL([',p.PartName,'],0) AS [', p.PartName,']') FROM #Parts p FOR XML PATH ('')),1,1,'')
--SELECT @HeaderColumns, @PivotColumns
DECLARE @sql nvarchar(max) = CONCAT('
SELECT MachineName,', @HeaderColumns ,
' FROM
(
SELECT m.MachineName, p.PartName, IIF(mpa.ID IS NULL, 0, 1) AS MachinePart FROM #Machine m
LEFT JOIN #MachinePartAssign mpa ON m.MachineID = mpa.MachineId
LEFT JOIN #Parts p ON p.PartID = mpa.PartID
) src
PIVOT
(
max(MachinePart) FOR PartName IN (',@PivotColumns,')
) pvt'
)
-- PRINT @sql
EXEC(@sql)
DROP TABLE #Machine
DROP TABLE #Parts
DROP TABLE #MachinePartAssign
链接演示:这是一个投影,在SQL中进行投影总是更好。因为机器和零件的每一个组合都有一个单元,这是极少数需要交叉连接的情况之一,所以
SELECT m.MachineName, p.PartName, IIF(mpa.id is null, 0, 1)
FROM Machines m CROSS JOIN Parts p
LEFT JOIN MachinePartAssign mpa
ON m.MachineId = mpa.MachineId and p.PartId = mpa.PartId
ORDER BY m.MachineId, p.PartId
我认为最好用C#构建表,因为动态sql选项对我来说很难理解和维护。回到你的应用程序中,你只需要在结果集中循环,每次MachineId发生变化时都会吐出一行新词
这是Rextester上的工具,多么酷的工具 这里是PIVOT函数的动态版本,以防零件表中的零件数超过3个:
declare @cols_part as nvarchar(max), @query as nvarchar(max)
select @cols_part = stuff((select distinct ',' + quotename(partname) from
parts for xml path(''), type ).value('.', 'nvarchar(max)') ,1,1,'')
set @query = 'select machinename, ' + @cols_part + '
from
(
select mp.machinename, mp.partname, iif(mpa.ID IS NULL,
0, 1) as machinepart
from ( select m.machineid, m.machinename, p.partid,
p.partname from machines m cross join
parts p ) mp
left join machinepartassign mpa on mp.machineid =
mpa.machineid and mp.partid = mpa.partid
) x
pivot ( max(machinepart) for partname in (' + @cols_part + ')
)p '
select @query -- to check the generated query
execute sp_executesql @query;
因为您需要在列中包含每个零件,即使没有特定机器的零件,我使用机器和零件之间的交叉联接,然后使用到machinepartassign表的左联接,以查找特定汽车是否有零件,如果有,则显示1
您可以看到此查询的结果。如果轴列和值列相同,也可以使用此查询:
SELECT MachineName, [Part 1], [Part 2], [Part 3]
FROM
(
SELECT m.MachineName, p.PartName
FROM dbo.MachinePartAssign a
INNER JOIN dbo.Parts p ON a.PartID = p.PartID
INNER JOIN dbo.Machines m ON a.MachineID = m.MachineID
) x
PIVOT
(
COUNT(PartName) FOR PartName IN ([Part 1], [Part 2], [Part 3])
) p
请格式化您的代码。你的问题是什么?它存储在哪个数据库中?完成-很抱歉。根据什么判断正确和错误,或者按1,2,3@Rambazamba如果机器和零件已分配,即机器中有匹配行,请将其分配为正确,否则其应为错误。在1次传递中,很容易获得0和1的正确/错误。是的,但如果您在部分中添加行,您需要更改sql?在这种情况下,您可以使用动态sql查询来计算pivot表的列非常感谢!SQL Server 2008 R2(应该在最初的问题中说明这一点)不支持CONCAT或IIF,但我设法将您的答案和rigertas答案结合起来,以满足我的需要。真棒的解决方案!非常感谢你!SQL Server 2008 R2(应该在最初的问题中说明这一点)不支持IIF,因此我使用了:“CASE WHEN(mpa.ID为NULL)然后0 ELSE 1结束为machinepart”。这应该是一样的。真棒的解决方案!是的,应该是这样。那太好了!快乐编码!:)