如何将父级和子级记录集合并到一个记录集中?

时间:2017-03-02 22:15:23

标签: sql sql-server excel ms-access data-manipulation

如果这是一个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个不同的代码,这也不是理想的。

4 个答案:

答案 0 :(得分:1)

假设您想要去DYNAMIC(未经测试)

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);
  

修改

如果列需要按特定顺序

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

答案 1 :(得分:0)

我认为您可以使用以下内容在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 ... lines ...这里的示例...... Excel SQL Building Example

您还可以使用能够处理块编辑的文本编辑器(例如Notepad ++)手动批量构建线条,方法是在块编辑模式下同时键入线条的重复部分(ALT + Click& Drag)。您也可以使用一些聪明的查找和替换操作来为您构建行。

最后,您可以使用自己喜欢的语言编写一个小循环并使用Distinct代码列表来构建SQL,我使用JavaScript构建了一个示例,这里有一个fiddle ,它应该可以直接从小提琴中使用。

答案 2 :(得分:0)

我比当前的数据结构要好得多,但是如果你必须这样做,你可以使用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字符串长度的限制。如果是这样,您可能需要弄清楚如何分割数据并将其分成几部分。

答案 3 :(得分:0)

这就是我最终做的事情,@ 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

至少达到了我的意图。用户仍然需要进行清理,但它比手动输入要好。