如何将父记录集和子记录集合并为一个记录集?
How do I join a parent and child recordsets into one recordset?
如果这是一个 DBA 问题,请随时告诉我。
我们有数据存储在需要导出的 SQL 数据库中,因此可以将其转换为新的软件包。目前,我们有一个父记录集和一个需要合并的子记录集,因为新系统能够跟踪父记录集的子记录集。我希望这是有道理的。
父记录集
ID | Description
-- | -----------
1 | Item 1
2 | Item 2
3 | Item 3
子记录集
Parent ID | Code | Value (string)
--------- | ----------- | -------------------
1 | PSI | 75
1 | SIZE | 2 1/2"
2 | CFM | 9200
2 | BELT | BROWING - A76
2 | RPM | 722
3 | PSI | 45
3 | SIZE | 1"
理想情况下,我们需要一个类似于以下内容的 CSV 文件(最后):
ID | Description | PSI | SIZE | CFM | BELT | RPM
-- | -----------
1 | Item 1
2 | Item 2
3 | Item 3
你明白了。
我不在乎它是在 SQL、Excel、Access 还是一些魔术(试图避免编写程序)中完成的,我正在努力节省它所花费的时间工作人员手动更改订单或输入订单。关于如何轻松更改的任何想法?我们说的是 5700 条子记录和 5900 条父记录。有什么 SQL 魔法可以做到这一点吗?
我确实考虑过单独添加每一列(例如 (select value from child where id = parent id and code = 'RPM') as RPM
),但是有 157 个不同的代码,这也不理想。
假设您想要动态(未测试)
Declare @SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(Code) From Child Order by 1 For XML Path('')),1,1,'')
Select @SQL = '
Select [ID],[Description],' + @SQL + '
From (
Select A.ID
,A.Description
,B.Code
,B.Value
From Parent A
Join Child B on (A.ID=B.ParentID)
) A
Pivot (max(Value) For [Code] in (' + @SQL + ') ) p'
Exec(@SQL);
EDIT
如果列需要按特定顺序排列
Select A.ID
,A.Description
,PSI = max(case when B.Code='PSI' then B.Value end)
,Size = max(case when B.Code='Size' then B.Value end)
,CFM = max(case when B.Code='CFM' then B.Value end)
-- ... more fields
From Parent A
Join Child B on (A.ID=B.ParentID)
Group By A.ID,A.Description
我认为您可以使用以下方法在 SQL 中实现它...
SELECT
parent_id AS `ID`,
MAX(CASE WHEN `code` = 'PSI' THEN `value` ELSE NULL END) AS `PSI`,
MAX(CASE WHEN `code` = 'SIZE' THEN `value` ELSE NULL END) AS `SIZE`,
MAX(CASE WHEN `code` = 'CFM' THEN `value` ELSE NULL END) AS `CFM`,
MAX(CASE WHEN `code` = 'BELT' THEN `value` ELSE NULL END) AS `BELT`,
MAX(CASE WHEN `code` = 'RPM' THEN `value` ELSE NULL END) AS `RPM`
FROM
`child`
GROUP BY
`parent_id`
尝试按照模式为您需要的每个字段创建一个 CASE。
MAX 是一个聚合函数,在这里使用它是为了避免额外的分组级别。
您可以处理大量代码,方法是首先使用...
获取代码列表
SELECT DISTINCT `code` from `child`
然后将结果复制到 Excel 并使用 CONCATENATE 函数构建 MAX(CASE...行...这里有一个示例...Excel SQL Building Example
您还可以使用能够处理块编辑的文本编辑器(例如 Notepad++)手动批量构建行,方法是在块编辑模式下同时键入行的重复部分(ALT + 单击并拖动)。您也可以使用一些巧妙的查找和替换操作来为您构建行。
最后,您可以通过使用您喜欢的语言编写一个小循环并使用 Distinct 代码列表来构建 SQL,我使用 JavaScript 构建了一个示例,这里是a fiddle 它应该可以直接从 fiddle.
中使用
我喜欢当前的数据结构比你要转换的数据结构好得多,但如果你必须这样做,你可以使用 VBA 循环遍历所有字段并创建一个 SQL字符串:
Function ConvertTable()
Set db = CurrentDb()
SQL = "Select ParentID"
Set RS = db.OpenRecordset("select Code from ChildRS group by Code")
RS.MoveFirst
Do While Not RS.EOF
code = RS.Fields("Code").Value
SQL = SQL & ", FIRST(iif(code='" & code & "',value)) as [" & code & "]"
RS.MoveNext
Loop
SQL = SQL & " Into [ConvertedTable] From ChildRS group by ParentID"
db.Execute SQL
MsgBox ("done")
End Function
这适用于您指定的少数代码 - 我不知道当您在所有字段上 运行 它是否会超过最大 SQL 字符串长度的限制。如果是这样,您可能需要弄清楚如何分割数据并将其分成几部分。
这是我最终所做的,有点像@JohnCappelletti 和此列表中其他人的合并。
首先我创建了一个包含所有可能代码的列表
select (REPLACE(REPLACE(REPLACE(c.Code, ' ', '_'), '.',''),'/','_') + ' =
max(case when d.Code = ''' + c.Code + ''' then d.Value else '''' end),') as text
from code_definitiions c
order by Code
该查询的输出是
AGMA = max(case when d.Code = 'AGMA' then d.Value1 else '' end),
AMB = max(case when d.Code = 'AMB' then d.Value1 else '' end),
AMB_T = max(case when d.Code = 'AMB T' then d.Value1 else '' end),
...
然后我将结果复制并粘贴到父查询中。
select m.ID, m.Description,
AGMA = max(case when d.Code = 'AGMA' then d.Value else '' end),
AMB = max(case when d.Code = 'AMB' then d.Value else '' end),
AMB_T = max(case when d.Code = 'AMB T' then d.Value else '' end),
... (the rest of the codes)
from parent m left outer join child d
on m.primary_key = d.foreign_key
group by m.ID, m.Description
order by m.ID
至少达到了我的预期。用户仍然需要清理,但比手动输入要好。
如果这是一个 DBA 问题,请随时告诉我。
我们有数据存储在需要导出的 SQL 数据库中,因此可以将其转换为新的软件包。目前,我们有一个父记录集和一个需要合并的子记录集,因为新系统能够跟踪父记录集的子记录集。我希望这是有道理的。
父记录集
ID | Description
-- | -----------
1 | Item 1
2 | Item 2
3 | Item 3
子记录集
Parent ID | Code | Value (string)
--------- | ----------- | -------------------
1 | PSI | 75
1 | SIZE | 2 1/2"
2 | CFM | 9200
2 | BELT | BROWING - A76
2 | RPM | 722
3 | PSI | 45
3 | SIZE | 1"
理想情况下,我们需要一个类似于以下内容的 CSV 文件(最后):
ID | Description | PSI | SIZE | CFM | BELT | RPM
-- | -----------
1 | Item 1
2 | Item 2
3 | Item 3
你明白了。
我不在乎它是在 SQL、Excel、Access 还是一些魔术(试图避免编写程序)中完成的,我正在努力节省它所花费的时间工作人员手动更改订单或输入订单。关于如何轻松更改的任何想法?我们说的是 5700 条子记录和 5900 条父记录。有什么 SQL 魔法可以做到这一点吗?
我确实考虑过单独添加每一列(例如 (select value from child where id = parent id and code = 'RPM') as RPM
),但是有 157 个不同的代码,这也不理想。
假设您想要动态(未测试)
Declare @SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(Code) From Child Order by 1 For XML Path('')),1,1,'')
Select @SQL = '
Select [ID],[Description],' + @SQL + '
From (
Select A.ID
,A.Description
,B.Code
,B.Value
From Parent A
Join Child B on (A.ID=B.ParentID)
) A
Pivot (max(Value) For [Code] in (' + @SQL + ') ) p'
Exec(@SQL);
EDIT
如果列需要按特定顺序排列
Select A.ID
,A.Description
,PSI = max(case when B.Code='PSI' then B.Value end)
,Size = max(case when B.Code='Size' then B.Value end)
,CFM = max(case when B.Code='CFM' then B.Value end)
-- ... more fields
From Parent A
Join Child B on (A.ID=B.ParentID)
Group By A.ID,A.Description
我认为您可以使用以下方法在 SQL 中实现它...
SELECT
parent_id AS `ID`,
MAX(CASE WHEN `code` = 'PSI' THEN `value` ELSE NULL END) AS `PSI`,
MAX(CASE WHEN `code` = 'SIZE' THEN `value` ELSE NULL END) AS `SIZE`,
MAX(CASE WHEN `code` = 'CFM' THEN `value` ELSE NULL END) AS `CFM`,
MAX(CASE WHEN `code` = 'BELT' THEN `value` ELSE NULL END) AS `BELT`,
MAX(CASE WHEN `code` = 'RPM' THEN `value` ELSE NULL END) AS `RPM`
FROM
`child`
GROUP BY
`parent_id`
尝试按照模式为您需要的每个字段创建一个 CASE。
MAX 是一个聚合函数,在这里使用它是为了避免额外的分组级别。
您可以处理大量代码,方法是首先使用...
获取代码列表SELECT DISTINCT `code` from `child`
然后将结果复制到 Excel 并使用 CONCATENATE 函数构建 MAX(CASE...行...这里有一个示例...Excel SQL Building Example
您还可以使用能够处理块编辑的文本编辑器(例如 Notepad++)手动批量构建行,方法是在块编辑模式下同时键入行的重复部分(ALT + 单击并拖动)。您也可以使用一些巧妙的查找和替换操作来为您构建行。
最后,您可以通过使用您喜欢的语言编写一个小循环并使用 Distinct 代码列表来构建 SQL,我使用 JavaScript 构建了一个示例,这里是a fiddle 它应该可以直接从 fiddle.
中使用我喜欢当前的数据结构比你要转换的数据结构好得多,但如果你必须这样做,你可以使用 VBA 循环遍历所有字段并创建一个 SQL字符串:
Function ConvertTable()
Set db = CurrentDb()
SQL = "Select ParentID"
Set RS = db.OpenRecordset("select Code from ChildRS group by Code")
RS.MoveFirst
Do While Not RS.EOF
code = RS.Fields("Code").Value
SQL = SQL & ", FIRST(iif(code='" & code & "',value)) as [" & code & "]"
RS.MoveNext
Loop
SQL = SQL & " Into [ConvertedTable] From ChildRS group by ParentID"
db.Execute SQL
MsgBox ("done")
End Function
这适用于您指定的少数代码 - 我不知道当您在所有字段上 运行 它是否会超过最大 SQL 字符串长度的限制。如果是这样,您可能需要弄清楚如何分割数据并将其分成几部分。
这是我最终所做的,有点像@JohnCappelletti 和此列表中其他人的合并。
首先我创建了一个包含所有可能代码的列表
select (REPLACE(REPLACE(REPLACE(c.Code, ' ', '_'), '.',''),'/','_') + ' =
max(case when d.Code = ''' + c.Code + ''' then d.Value else '''' end),') as text
from code_definitiions c
order by Code
该查询的输出是
AGMA = max(case when d.Code = 'AGMA' then d.Value1 else '' end),
AMB = max(case when d.Code = 'AMB' then d.Value1 else '' end),
AMB_T = max(case when d.Code = 'AMB T' then d.Value1 else '' end),
...
然后我将结果复制并粘贴到父查询中。
select m.ID, m.Description,
AGMA = max(case when d.Code = 'AGMA' then d.Value else '' end),
AMB = max(case when d.Code = 'AMB' then d.Value else '' end),
AMB_T = max(case when d.Code = 'AMB T' then d.Value else '' end),
... (the rest of the codes)
from parent m left outer join child d
on m.primary_key = d.foreign_key
group by m.ID, m.Description
order by m.ID
至少达到了我的预期。用户仍然需要清理,但比手动输入要好。