我有一个包含这些列的表Farm
FarmID:(primary)
Kenizy:
BarBedo:
BarBodo:
MorKodo:
这些列是某种语言的手掌类型。其中的每一列都包含一个数字,表示农场内此类棕榈的数量。
示例:
FarmID | Kenizy | BarBedo | BarBodo | MorKodo
-----------------------------------------------
3 | 20 | 12 | 45 | 60
22 | 21 | 9 | 41 | 3
我想将该表插入下表:
表Palm_Farm
FarmID:(primary)
PalmID;(primary)
PalmTypeName:
Count:
该表将每个农场与每种手掌类型连接起来。
示例:
FarmID | PalmID | PalmTypeName | Count
-----------------------------------------------
3 | 1 | Kenizy | 20
3 | 2 | BarBedo | 12
3 | 3 | BarBodo | 45
3 | 4 | MorKodo | 60
22 | 1 | Kenizy | 21
22 | 2 | BarBedo | 9
22 | 3 | BarBodo | 41
22 | 4 | MorKodo | 3
我必须使用下表Palms
才能获取PalmID
列。
PalmID:(primary)
PlamTypeName:
...other not important columns
此表用于保存有关每种手掌类型的信息。
示例:
PalmID | PlamTypeName
-------------------------
1 | Kenizy
2 | BarBedo
3 | BarBodo
4 | MorKodo
PalmTypeName
列的值与Farm
表中的 COLUMN NAMES 相同。
所以我的问题是:
考虑到Farm
表中存在PalmID,如何将Palm_Farm
表中的数据插入Palm
我希望我可以明白我的问题,我自己尝试解决问题,但Farm
表中的列名必须是column value
in Palm_Farm
表无法知道如何操作。
我无法更改表结构,因为我们正在尝试使用此已存在的表来帮助客户
我正在使用SQL Server 2008,因此欢迎使用Merge
。
天才回答@GarethD
之后,我得到了这个例外
答案 0 :(得分:2)
您可以使用UNPIVOT将列转换为行:
INSERT Palm_Farm (FarmID, PalmID, PalmTypeName, [Count])
SELECT upvt.FarmID,
p.PalmID,
p.PalmTypeName,
upvt.[Count]
FROM Farm AS f
UNPIVOT
( [Count]
FOR PalmTypeName IN ([Kenizy], [BarBedo], [BarBodo], [MorKodo])
) AS upvt
INNER JOIN Palms AS p
ON p.PalmTypeName = upvt.PalmTypeName;
<强> Example on SQL Fiddle 强>
UNPIVOT
州的文档:
UNPIVOT通过将列旋转到行中来执行几乎PIVOT的反向操作。假设前一个示例中生成的表作为pvt存储在数据库中,并且您希望将列标识符Emp1,Emp2,Emp3,Emp4和Emp5旋转为与特定供应商对应的行值。这意味着您必须识别另外两列。包含要旋转的列值的列(Emp1,Emp2,...)将被称为Employee,并且将保存当前位于要旋转的列下的值的列将被称为Orders。这些列分别对应于Transact-SQL定义中的pivot_column和value_column。
为了进一步解释unpivot如何工作,我将看第一行原始表:
FarmID | Kenizy | BarBedo | BarBodo | MorKodo
-----------------------------------------------
3 | 20 | 12 | 45 | 60
所以UPIVOT会做的是查找UNPIVOT
语句中指定的列,并为每列创建一行:
SELECT upvt.FarmID, upvt.PalmTypeName, upvt.[Count]
FROM Farm AS f
UNPIVOT
( [Count]
FOR PalmTypeName IN ([Kenizy], [BarBedo])
) AS upvt;
所以在这里你要说的是,对于每一行都找到列[Kenizy]
和[BarBedo]
并为每个行创建一行,然后为每个行创建一个名为PalmTypeName
的新列,将包含使用的列名,然后将该列的值放入名为[Count]的新列中。给出结果:
FarmID | Kenizy | Count |
---------------------------
3 | Kenizy | 20 |
3 | BarBedo | 12 |
如果您运行的是SQL Server 2000或兼容级别较低的更高版本,则可能需要使用其他查询:
INSERT Palm_Farm (FarmID, PalmID, PalmTypeName, [Count])
SELECT f.FarmID,
p.PalmID,
p.PalmTypeName,
[Count] = CASE upvt.PalmTypeName
WHEN 'Kenizy' THEN f.Kenizy
WHEN 'BarBedo' THEN f.BarBedo
WHEN 'BarBodo' THEN f.BarBodo
WHEN 'MorKodo' THEN f.MorKodo
END
FROM Farm AS f
CROSS JOIN
( SELECT PalmTypeName = 'Kenizy' UNION ALL
SELECT PalmTypeName = 'BarBedo' UNION ALL
SELECT PalmTypeName = 'BarBodo' UNION ALL
SELECT PalmTypeName = 'MorKodo'
) AS upvt
INNER JOIN Palms AS p
ON p.PalmTypeName = upvt.PalmTypeName;
这类似,但您必须使用子查询UNION ALL
内的upvt
自行创建其他行,然后使用案例表达式选择[Count]
的值。
要在行存在时更新,您可以使用MERGE
WITH Data AS
( SELECT upvt.FarmID,
p.PalmID,
p.PalmTypeName,
upvt.[Count]
FROM Farm AS f
UNPIVOT
( [Count]
FOR PalmTypeName IN ([Kenizy], [BarBedo], [BarBodo], [MorKodo])
) AS upvt
INNER JOIN Palms AS p
ON p.PalmTypeName = upvt.PalmTypeName
)
MERGE Palm_Farm WITH (HOLDLOCK) AS pf
USING Data AS d
ON d.FarmID = pf.FarmID
AND d.PalmID = pf.PalmID
WHEN NOT MATCHED BY TARGET THEN
INSERT (FarmID, PalmID, PalmTypeName, [Count])
VALUES (d.FarmID, d.PalmID, d.PalmTypeName, d.[Count])
WHEN MATCHED THEN
UPDATE
SET [Count] = d.[Count],
PalmTypeName = d.PalmTypeName;