SQL : 将多个左连接行输出为 csv 文件的一条记录
SQL : Output multiple left joined rows as one record for csv file
我有 3 个 tables :
Stock - ID, Description, Quantity etc
Equipment - ID, Description
LinkStockEquipment - StockID, EquipmentID, Quantity
每个库存项目可能需要多种类型的设备。
我想将所有数据输出到一个csv文件中给客户。
理想情况下他们想要:
StockID、StockDescription、StockQuantity、Equipment1、Equipment1Qty、Equipment2、Equipment2Qty、Equipment3、Equipment3Qty 等
所以我的出发点是:
SELECT * FROM Stock
LEFT JOIN LinkStockEquipment ON LinkStockEquipment.StockID = Stock.ID
LEFT JOIN Equipment ON Equipment.ID = LinkStockEquipment.EquipmentID
当然,当每个库存项目有多种类型的设备时,这只会给我多行。我可以使用 SORT 和 MAX 或 MIN 来获取顶部或底部的行,但是我将如何访问剩余的行,一个接一个地 link 它们。
会不会像(语法错误但试图传达信息)
SELECT * FROM Stock
LEFT JOIN LinkStockEquipment AS LSE1 ON LSE1.StockID = Stock.ID LIMIT 1
LEFT JOIN LinkStockEquipment AS LSE2 ON LSE2.StockID = Stock.ID AND LSE1.StockID <> LSE2.StockID LIMIT 1
LEFT JOIN LinkStockEquipment AS LSE3 ON LSE3.StockID = Stock.ID AND LSE1.StockID <> LSE2.StockID AND LSE2.StockID <> LSE3.StockID LIMIT 1
LEFT JOIN Equipment ON Equipment.ID = LinkStockEquipment.EquipmentID
很抱歉,如果这已经被直接回答了,我之前只使用过基本的SQL,所以我没有完全理解类似问题的其他答案。
MySQL Left Join Many to One Row可能会做我想做的事,但我还需要每种设备的数量,所以这似乎不是解决方案。
更新 1:
我也查看了 MySQL pivot row into dynamic number of columns,但是当我每次都需要设备和数量而不是只需要一个项目时,我没有看到它如何应用。我会阅读更多关于 Pivoting 的内容。
更新二:
阅读有关 pivoting 的信息,它会为每种设备类型提供一个单独的列,但可能有 100 种不同的设备类型。但是,在这 100 种不同类型中,每个库存商品可能只有 2 种或 3 种。因此我只想列出那些设备类型,而不是每个列。
给定:
Stock ID | Equipment ID | Equipment Qty
---------------------------------------
A1 | E1 | 5
A1 | E2 | 3
A2 | E3 | 4
A2 | E4 | 6
A3 | E5 | 2
我愿意
Stock ID | Eqpmnt ID 1 | Eqpmnt Qty 1 | Eqpmnt ID 2 | Eqpmnt Qty 2
------------------------------------------------------------------
A1 | E1 | 5 | E2 | 3
A2 | E3 | 4 | E4 | 6
A3 | E5 | 2 | |
没有
Stock ID | E1 | E2 | E3 | E4 | E5
------------------------------------------------------------------
A1 | 5 | 3 | | |
A2 | | | 4 | 6 |
A3 | | | | | 2
除非我误解了旋转?
更新和结果:
出于某种原因,我无法将其设置为问题的答案,但是万一这对其他人有帮助...
感谢下面的 Juan,我使用这个问题的信息在我的 LinkStockEquipment table 中添加了一行:
UPDATE t1
SET t1.Counter = t2.Counter
FROM LinkStockEquipment t1
LEFT JOIN
(
SELECT
t.EquipmentID,
t.StockID ,
(SELECT COUNT(*) FROM [LinkStockEquipment] AS x WHERE x.EquipmentID <= t.EquipmentID
AND x.StockID = t.StockID) AS Counter
FROM [LinkStockEquipment] t
) as t2
ON t1.EquipmentID= t2.EquipmentID AND t1.StockID = t2.StockID
那么 table 看起来像:
Stock ID | Equipment ID | Equipment Qty | Counter
-------------------------------------------------
A1 | E1 | 5 | 1
A1 | E2 | 3 | 2
A2 | E3 | 4 | 1
A2 | E4 | 6 | 2
A3 | E5 | 2 | 1
现在我可以旋转了,所以使用
SELECT P.StockID, P.[1], L1.Qty, P.[2], L2.Qty, P.[3], L3.Qty
FROM (SELECT StockID, EquipmentID, Counter
FROM [LinkStockEquipment]) AS D
PIVOT(MAX(EquipmentID) FOR Counter IN([1],[2],[3])) AS P
LEFT JOIN [LinkStockEquipment] L1 ON L1.StockID = P.StockID
AND L1.EquipmentID = P.[1]
LEFT JOIN [LinkStockEquipment] L2 ON L2.StockID = P.StockID
AND L2.EquipmentID = P.[2]
LEFT JOIN [LinkStockEquipment] L3 ON L3.StockID = P.StockID
AND L3.EquipmentID = P.[3]
我可以加入 Stock table 详细信息,我得到了想要的结果。
如果您有固定数量的库存设备(我假设为 3 个)
您可以使用 GROUP BY
进行转轴。
WITH tmpResult as (
SELECT
[Stock ID],
'Equipment ID ' + CAST(rn AS VARCHAR(16)) as lblEq,
[Equipment ID],
[Equipment Qty]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
)
SELECT [Stock ID],
MAX( CASE WHEN lblEq = 'Equipment ID 1' THEN [Equipment ID] END) as [Eqp ID 1],
MAX( CASE WHEN lblEq = 'Equipment ID 1' THEN [Equipment Qty] END) as [Eqp Qty 1],
MAX( CASE WHEN lblEq = 'Equipment ID 2' THEN [Equipment ID] END) as [Eqp ID 2],
MAX( CASE WHEN lblEq = 'Equipment ID 2' THEN [Equipment Qty] END) as [Eqp Qty 2],
MAX( CASE WHEN lblEq = 'Equipment ID 3' THEN [Equipment ID] END) as [Eqp ID 3],
MAX( CASE WHEN lblEq = 'Equipment ID 3' THEN [Equipment Qty] END) as [Eqp Qty 3]
FROM tmpResult
GROUP BY [Stock ID];
输出
现在,如果您想使用 PIVOT,重要的部分是数据准备。在这种情况下,我必须将数量转换为字符串。同样,您需要知道要转换的字段数
WITH tmpResult as (
SELECT
[Stock ID],
'Eqp ID ' + CAST(rn AS VARCHAR(16)) as label,
[Equipment ID] as [Value]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
UNION ALL
SELECT
[Stock ID],
'Eqp Qty ' + CAST(rn AS VARCHAR(16)) as label,
CAST([Equipment Qty] AS VARCHAR(16)) as [Value]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
)
SELECT [Stock ID],
[Eqp ID 1], [Eqp Qty 1],
[Eqp ID 2], [Eqp Qty 2]
FROM ( SELECT * FROM tmpResult ) as x
PIVOT (
max( [Value] )
for label in ( [Eqp ID 1], [Eqp Qty 1], [Eqp ID 2], [Eqp Qty 2] )
) as pvt
输出
现在如果你不知道你有多少设备,那么你需要动态 PIVOT。
首先你需要一个时间table。
SELECT
[Stock ID],
[label],
[Value]
INTO tmpResult
FROM (
SELECT
[Stock ID],
'Eqp ID ' + CAST(rn AS VARCHAR(16)) as label,
[Equipment ID] as [Value]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
UNION ALL
SELECT
[Stock ID],
'Eqp Qty ' + CAST(rn AS VARCHAR(16)) as label,
CAST([Equipment Qty] AS VARCHAR(16)) as [Value]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
) as x;
然后你需要准备数据透视查询:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.label)
FROM tmpResult c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SELECT @cols;
set @query = 'SELECT [Stock ID], ' + @cols + ' FROM
(
SELECT *
FROM tmpResult
) x
pivot
(
max(Value)
for label in (' + @cols + ')
) p '
execute(@query);
输出
这里的问题是列顺序。我试试看能不能修好。
我有 3 个 tables :
Stock - ID, Description, Quantity etc
Equipment - ID, Description
LinkStockEquipment - StockID, EquipmentID, Quantity
每个库存项目可能需要多种类型的设备。
我想将所有数据输出到一个csv文件中给客户。
理想情况下他们想要:
StockID、StockDescription、StockQuantity、Equipment1、Equipment1Qty、Equipment2、Equipment2Qty、Equipment3、Equipment3Qty 等
所以我的出发点是:
SELECT * FROM Stock
LEFT JOIN LinkStockEquipment ON LinkStockEquipment.StockID = Stock.ID
LEFT JOIN Equipment ON Equipment.ID = LinkStockEquipment.EquipmentID
当然,当每个库存项目有多种类型的设备时,这只会给我多行。我可以使用 SORT 和 MAX 或 MIN 来获取顶部或底部的行,但是我将如何访问剩余的行,一个接一个地 link 它们。
会不会像(语法错误但试图传达信息)
SELECT * FROM Stock
LEFT JOIN LinkStockEquipment AS LSE1 ON LSE1.StockID = Stock.ID LIMIT 1
LEFT JOIN LinkStockEquipment AS LSE2 ON LSE2.StockID = Stock.ID AND LSE1.StockID <> LSE2.StockID LIMIT 1
LEFT JOIN LinkStockEquipment AS LSE3 ON LSE3.StockID = Stock.ID AND LSE1.StockID <> LSE2.StockID AND LSE2.StockID <> LSE3.StockID LIMIT 1
LEFT JOIN Equipment ON Equipment.ID = LinkStockEquipment.EquipmentID
很抱歉,如果这已经被直接回答了,我之前只使用过基本的SQL,所以我没有完全理解类似问题的其他答案。
MySQL Left Join Many to One Row可能会做我想做的事,但我还需要每种设备的数量,所以这似乎不是解决方案。
更新 1: 我也查看了 MySQL pivot row into dynamic number of columns,但是当我每次都需要设备和数量而不是只需要一个项目时,我没有看到它如何应用。我会阅读更多关于 Pivoting 的内容。
更新二: 阅读有关 pivoting 的信息,它会为每种设备类型提供一个单独的列,但可能有 100 种不同的设备类型。但是,在这 100 种不同类型中,每个库存商品可能只有 2 种或 3 种。因此我只想列出那些设备类型,而不是每个列。
给定:
Stock ID | Equipment ID | Equipment Qty
---------------------------------------
A1 | E1 | 5
A1 | E2 | 3
A2 | E3 | 4
A2 | E4 | 6
A3 | E5 | 2
我愿意
Stock ID | Eqpmnt ID 1 | Eqpmnt Qty 1 | Eqpmnt ID 2 | Eqpmnt Qty 2
------------------------------------------------------------------
A1 | E1 | 5 | E2 | 3
A2 | E3 | 4 | E4 | 6
A3 | E5 | 2 | |
没有
Stock ID | E1 | E2 | E3 | E4 | E5
------------------------------------------------------------------
A1 | 5 | 3 | | |
A2 | | | 4 | 6 |
A3 | | | | | 2
除非我误解了旋转?
更新和结果: 出于某种原因,我无法将其设置为问题的答案,但是万一这对其他人有帮助...
感谢下面的 Juan,我使用这个问题的信息在我的 LinkStockEquipment table 中添加了一行:
UPDATE t1
SET t1.Counter = t2.Counter
FROM LinkStockEquipment t1
LEFT JOIN
(
SELECT
t.EquipmentID,
t.StockID ,
(SELECT COUNT(*) FROM [LinkStockEquipment] AS x WHERE x.EquipmentID <= t.EquipmentID
AND x.StockID = t.StockID) AS Counter
FROM [LinkStockEquipment] t
) as t2
ON t1.EquipmentID= t2.EquipmentID AND t1.StockID = t2.StockID
那么 table 看起来像:
Stock ID | Equipment ID | Equipment Qty | Counter
-------------------------------------------------
A1 | E1 | 5 | 1
A1 | E2 | 3 | 2
A2 | E3 | 4 | 1
A2 | E4 | 6 | 2
A3 | E5 | 2 | 1
现在我可以旋转了,所以使用
SELECT P.StockID, P.[1], L1.Qty, P.[2], L2.Qty, P.[3], L3.Qty
FROM (SELECT StockID, EquipmentID, Counter
FROM [LinkStockEquipment]) AS D
PIVOT(MAX(EquipmentID) FOR Counter IN([1],[2],[3])) AS P
LEFT JOIN [LinkStockEquipment] L1 ON L1.StockID = P.StockID
AND L1.EquipmentID = P.[1]
LEFT JOIN [LinkStockEquipment] L2 ON L2.StockID = P.StockID
AND L2.EquipmentID = P.[2]
LEFT JOIN [LinkStockEquipment] L3 ON L3.StockID = P.StockID
AND L3.EquipmentID = P.[3]
我可以加入 Stock table 详细信息,我得到了想要的结果。
如果您有固定数量的库存设备(我假设为 3 个)
您可以使用 GROUP BY
进行转轴。
WITH tmpResult as (
SELECT
[Stock ID],
'Equipment ID ' + CAST(rn AS VARCHAR(16)) as lblEq,
[Equipment ID],
[Equipment Qty]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
)
SELECT [Stock ID],
MAX( CASE WHEN lblEq = 'Equipment ID 1' THEN [Equipment ID] END) as [Eqp ID 1],
MAX( CASE WHEN lblEq = 'Equipment ID 1' THEN [Equipment Qty] END) as [Eqp Qty 1],
MAX( CASE WHEN lblEq = 'Equipment ID 2' THEN [Equipment ID] END) as [Eqp ID 2],
MAX( CASE WHEN lblEq = 'Equipment ID 2' THEN [Equipment Qty] END) as [Eqp Qty 2],
MAX( CASE WHEN lblEq = 'Equipment ID 3' THEN [Equipment ID] END) as [Eqp ID 3],
MAX( CASE WHEN lblEq = 'Equipment ID 3' THEN [Equipment Qty] END) as [Eqp Qty 3]
FROM tmpResult
GROUP BY [Stock ID];
输出
现在,如果您想使用 PIVOT,重要的部分是数据准备。在这种情况下,我必须将数量转换为字符串。同样,您需要知道要转换的字段数
WITH tmpResult as (
SELECT
[Stock ID],
'Eqp ID ' + CAST(rn AS VARCHAR(16)) as label,
[Equipment ID] as [Value]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
UNION ALL
SELECT
[Stock ID],
'Eqp Qty ' + CAST(rn AS VARCHAR(16)) as label,
CAST([Equipment Qty] AS VARCHAR(16)) as [Value]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
)
SELECT [Stock ID],
[Eqp ID 1], [Eqp Qty 1],
[Eqp ID 2], [Eqp Qty 2]
FROM ( SELECT * FROM tmpResult ) as x
PIVOT (
max( [Value] )
for label in ( [Eqp ID 1], [Eqp Qty 1], [Eqp ID 2], [Eqp Qty 2] )
) as pvt
输出
现在如果你不知道你有多少设备,那么你需要动态 PIVOT。
首先你需要一个时间table。
SELECT
[Stock ID],
[label],
[Value]
INTO tmpResult
FROM (
SELECT
[Stock ID],
'Eqp ID ' + CAST(rn AS VARCHAR(16)) as label,
[Equipment ID] as [Value]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
UNION ALL
SELECT
[Stock ID],
'Eqp Qty ' + CAST(rn AS VARCHAR(16)) as label,
CAST([Equipment Qty] AS VARCHAR(16)) as [Value]
FROM ( SELECT *, row_number() over (partition by [Stock ID] ORDER BY [Equipment ID]) as rn
FROM LinkStockEquipment ) as rows
) as x;
然后你需要准备数据透视查询:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.label)
FROM tmpResult c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SELECT @cols;
set @query = 'SELECT [Stock ID], ' + @cols + ' FROM
(
SELECT *
FROM tmpResult
) x
pivot
(
max(Value)
for label in (' + @cols + ')
) p '
execute(@query);
输出
这里的问题是列顺序。我试试看能不能修好。