我无法理解以下问题的解决方案: 我有三个表(MS SQL):
机器
+-----------+-------------+
| MachineID | MachineName |
+-----------+-------------+
| 1 | Press 1 |
| 2 | Press 2 |
| 3 | Press 3 |
+-----------+-------------+
零件
+-----------+-------------+
| PartID | PartName |
+-----------+-------------+
| 1 | Part 1 |
| 2 | Part 2 |
| 3 | Part 3 |
+-----------+-------------+
MachinePartAssign
+----+-----------+--------+--+
| ID | MachineId | PartID | |
+----+-----------+--------+--+
| 1 | 1 | 1 | |
| 2 | 1 | 2 | |
| 3 | 1 | 3 | |
| 4 | 2 | 2 | |
| 5 | 3 | 2 | |
| 6 | 3 | 3 | |
+----+-----------+--------+--+
这就是我想得到的查询结果: (如果分配了机器和零件,则 MachinePartAssign 中的匹配行 true (或 1 )时会出现这种情况,否则应该是 false (或 0 )。我还可以为每个零件/机器组合插入一行到 MachinePartAssign 并包含一个额外的布尔值(位)如果这使得它更容易。我仍然需要类似的数据透视查询。(?))
期望结果(如果更容易,则可以用1和0交换true或false)
+-----------+--------+--------+--------+
| | Part 1 | Part 2 | Part 3 |
| Press 1 | true | true | true |
| Press 2 | false | true | false |
| Press 3 | false | true | true |
+-----------+--------+--------+--------+
目前我正在使用c#中的循环执行此操作:首先选择每台机器,然后选择所有部件,然后为该特定机器/部件组合选择MachinePartAssign。如果我得到> 1行返回它的真实。这意味着每个机器/部件都有一个查询。
我确信这是一种更优雅的方式。我知道MSSQL提供了PIVOT功能,但我不确定如何在我的情况下使用它。
非常感谢!
答案 0 :(得分:1)
也许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
此查询的结果:In rextester
如果表部件可以添加其他项,则可以像这样使用动态SQL查询
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
链接演示:Dynamic pivot
答案 1 :(得分:0)
这是一个投影,你总是更好地在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的full working example,这是一个很酷的工具!
答案 2 :(得分:0)
这是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.
Here
您可以看到此查询的结果。
答案 3 :(得分:0)
如果pivot列和valu列相同,它也可以工作:
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