从单个表的一行中添加多行

Posted

技术标签:

【中文标题】从单个表的一行中添加多行【英文标题】:Add multiple rows in just one row from a single table 【发布时间】:2012-07-16 17:27:52 【问题描述】:

如何通过mysql在一行中加入多行?

例子:

学生桌

Sno.| Name  |  Subjects
1.  | ABC   |  English
2.  | ABC   |  Mathematics
3.  | ABC   |  Science
4.  | FMC |  French
5.  | ABC   |  Russian
6.  | JBC   |  French

现在我想要这种格式

Sno.| Name |   Sub1 |  Sub2 | Sub3 |  Sub4 |
1.  | ABC |   Eng  |  Maths| Science| Russian
2.  | FMC |    French| Null| Null   | Null
3.  | JBC |   French| Null | Null   | Null

我不知道实际上该怎么做?我应该创建一个视图还是一个表?

我想风景会很好。

【问题讨论】:

您真的需要单独的列吗?否则你可以使用GROUP_CONCAT。之后您想如何处理这些数据? 看看这个:***.com/questions/7674786/mysql-pivot-table 我想用 fpdf 制作 pdf 格式的报告。 @IPerfect : 以 pdf 格式打印,您使用的是哪种语言? @FahimParkar 对于 pdf,我使用 php 和 FPDF。 【参考方案1】:

我同意其他答案,GROUP_CONCAT 与 PHP 一起拆分逗号分隔值可能是最好的方法,但是如果出于任何其他原因您需要通过 Pure SQL 建议的输出,我会建议其中之一以下方法。

1. Self Joins

SELECT  t1.Name, 
        MIN(t1.Subject) AS Sub1,
        MIN(t2.Subject) AS Sub2,
        MIN(t3.Subject) AS Sub3,
        MIN(t4.Subject) AS Sub4
FROM    Students t1
        LEFT JOIN Students T2 
            ON t1.Name = t2.Name 
            AND t2.Subject > t1.Subject
        LEFT JOIN Students T3 
            ON t2.Name = t3.Name 
            AND t3.Subject > t2.Subject
        LEFT JOIN Students T4 
            ON t3.Name = t4.Name 
            AND t4.Subject > t3.Subject
GROUP BY t1.Name;

2. Using a ROW_NUMBER Type function to aggregate

SELECT   Name,
         MAX(IF(RowNum = 1,Subject, NULL)) AS Sub1,
         MAX(IF(RowNum = 2,Subject, NULL)) AS Sub2,
         MAX(IF(RowNum = 3,Subject, NULL)) AS Sub3,
         MAX(IF(RowNum = 4,Subject, NULL)) AS Sub4
FROM     (    SELECT   Name,
                       Subject,
                       @r:= IF(@Name = Name, @r + 1, 1) AS RowNum,
                       @Name:= Name AS Name2
              FROM    Students,
                      (SELECT @Name:='') n,
                      (SELECT @r:= 0) r
              ORDER BY Name, Sno
          ) t
GROUP BY Name

【讨论】:

【参考方案2】:

使用以下查询,获取姓名和他/她的主题。

SELECT Name, GROUP_CONCAT(Subjects) AS List
FROM myTable
GROUP BY Name

然后在PHP中,你可以使用implode函数来打印主题。

希望这会有所帮助。

Demo at sqlfiddle

【讨论】:

【参考方案3】:

尝试使用 GROUP BY 和 GROUP_CONCAT:

SELECT Name, GROUP_CONCAT(Subjects) AS Subjects_list
FROM students_table
GROUP BY Name

然后在获取记录时使用PHP函数explode来获取存储在Subjects_list列中的不同值。

【讨论】:

嗯,让我检查一下。感谢您的帮助。【参考方案4】:

不漂亮!

要使用上述解决方案,您可以这样做:

SELECT 
  Sno, 
  Name,
  NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(all_subjects, ',', 1), ',', -1), '') AS Sub1,
  NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(all_subjects, ',', 2), ',', -1), '') AS Sub2,
  NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(all_subjects, ',', 3), ',', -1), '') AS Sub3,
  NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(all_subjects, ',', 4), ',', -1), '') AS Sub4
FROM (
  SELECT Sno, Name, CONCAT(GROUP_CONCAT(Subjects ORDER BY Sno),',,,') AS all_subjects FROM table GROUP BY name
) inner_sel
;

您的请求导致假设主题永远不会超过 4 个。您还需要NULLs,其中没有提及四个主题。

有些请求会导致强制执行 SQL 代码,这通常是 SQL 的用途。

为了解释上面的内容:我们使用GROUP_CONCAT,然后再次将其分解。由于可能少于 4 个元素,我们用逗号 (',,,') 填充。然后我们根据它在连接字符串中的位置分解每个部分,如果它是空的,则返回 NULL

不能说这是我在漂亮方面更好的答案之一。我希望你觉得它有用。

【讨论】:

我可以用这个创建一个视图吗? 由于派生表,您必须创建两个视图。因此,内部 SELECT 的视图,另一个从中读取的视图。

以上是关于从单个表的一行中添加多行的主要内容,如果未能解决你的问题,请参考以下文章

SQL Join 与单个表的多行

如何从返回主键多行的连接中选择第一行

Hive一行拆多行、多行拼一行

如何在单个查询中使用联接和聚合函数更新表中的多行

在单个波段中具有多行时,数据溢出会拉伸一行

BufferedReader:将多行读入单个字符串