使用列

时间:2016-01-12 10:40:59

标签: mysql sql

我被要求进行查询,但这是他们第一次问我这种查询。另外,我不知道如何命名这个问题的标题,所以我想道歉,以防它可能会产生误导。

所以,首先我有两个名为Article和Attribute的表,其关系是多对多的。其中每个都具有以下结构(最重要的列),并带有一些示例:

Article Table                                Attribute Table
--------------                 -----------------------------------------
| Article_id |                 |Attribute_id| Attribute_Name| Data_type|
|  Article1  |                 |      1     | Article_name  |   Text   |
|  Article2  |                 |      2     |    Height     |   Number |
|  Article3  |                 |      3     |  Description  |  Fulltext|
--------------                 -----------------------------------------

如您所见,Article表仅包含文章ID,而其属性的其余部分(如名称或描述)可在Attribute表中找到。 此外,并非所有文章都应具备所有属性。最后但并非最不重要的是,有大量的文章和大量的属性(超过30个),但我只是把几个作为例子。

现在,Article_Attribute表有点混乱,因为它是多年前制作的。它有这个结构,有一些例子:

                          Article_Attribute table
-------------------------------------------------------------------------
| Article_ID | Attribute_ID | Number_Value | Text_Value | Fulltext_Value |
--------------------------------------------------------------------------
|  Article1  |   Attribute1 |     NULL     | Tennis Ball|       NULL     |
|  Article1  |   Attribute3 |     NULL     |    NULL    |   Just a ball  |
|  Article2  |   Attribute1 |     NULL     |   Eraser   |       NULL     |
|  Article2  |   Attribute3 |     NULL     |    NULL    |  Paper eraser  |
|  Article3  |   Attribute1 |     13       |    NULL    |       NULL     |
|  Article3  |   Attribute2 |     NULL     |    Pencil  |       NULL     |
|  Article3  |   Attribute3 |     NULL     |    NULL    | A simple pencil|
--------------------------------------------------------------------------

因此它为每个属性的data_type包含三列而不是一个单值列。

现在我需要一个查询来获得这样的结果:

--------------------------------------------------------------------------
| Article_ID | Article_Name |Article_Height|    Article_Description      |
--------------------------------------------------------------------------
|  Article1  |  Tennis Ball |     NULL     |         Just a ball         |
|  Article2  |    Eraser    |     NULL     |         Paper eraser        |
|  Article3  |    Pencil    |      13      |       A simple pencil       |
--------------------------------------------------------------------------

到目前为止,我有这么简单的查询:

select a.article_id, attr.attribute_name, ae.number_value, ae.text_value, ae.fulltext_value 
    FROM article as a 
    LEFT JOIN article_attribute as ae ON a.article_id = ae.article_id 
    LEFT JOIN attribute as attr ON ae.attribute_id = attr.id 
ORDER BY a.article_id ASC 

这给了我一些东西..

----------------------------------------------------------------------------
| Article_ID | Attribute_name | Number_Value | Text_Value | Fulltext_Value |
----------------------------------------------------------------------------
|  Article1  |  Article_name  |     NULL     | Tennis Ball|     NULL       |
|  Article1  |   Description  |     NULL     |    NULL    |   Just a ball  |
|  Article2  |   Article_name |     NULL     |   Eraser   |       NULL     |
|  Article2  |   Description  |     NULL     |    NULL    |  Paper eraser  |
|  Article3  |   Article_name |     13       |    NULL    |       NULL     |
|  Article3  |     Height     |     NULL     |    Pencil  |       NULL     |
|  Article3  |   Description  |     NULL     |    NULL    | A simple pencil|
----------------------------------------------------------------------------

这基本上是我可以去的,因为我对查询不好......

我该怎么办?我应该使用存储过程吗?如何将属性名称作为列?

非常感谢任何帮助,我想提前感谢你。

修改: 我没有注意到属性表上的一个大细节:有一些属性实际上有其他表作为Data_type(哦天啊..)。例如,有颜色属性:

              Attribute Table
------------------------------------------
|Attribute_id| Attribute_Name| Data_type |
|      1     | Article_name  |   Text    |
|      2     |    Height     |   Number  |
|      3     |  Description  |  Fulltext |
|      4     |     Color     |Color_Table|
------------------------------------------

在这张桌子上,我们只找到color_id及其名称,如:

        Color Table
------------------------------
|      ID    |      Name     |
|      1     |      White    |
|      2     |      Black    |
------------------------------

在article_attribute表中,您可以在Number_value列中找到关系的值。

还可以吗?有6个属性实际链接到其他表。如果这是不可能的,因为这个数据库真的搞砸了很多年前已经搞好了,那么没关系,我仍然会欣赏并接受你的回答。

2 个答案:

答案 0 :(得分:2)

您尝试执行的操作称为" pivot"。

虽然其他一些RDBMS本身提供了有效的语法来实现这样的操作,但MySQL却没有 - 它的开发人员认为这种数据操作纯粹是表示性的,因此更适合于更高层的应用程序代码,而不是与之相关的东西。数据库应该负担。

如果绝对必须在MySQL中执行数据透视,那么以真正动态的方式完成它的唯一方法(即不使用属性或其数据类型的任何预知)是通过使用&# 34;动态SQL" -ie从最初操作的结果动态组装最终的DML语句。我们希望执行的最终声明如下所示:

SELECT   aa.Article_ID,
         GROUP_CONCAT(IF(
           a.Attribute_Name = 'Name', 
           aa.Text_Value,
           NULL
         )) AS Article_Name,
         GROUP_CONCAT(IF(
           a.Attribute_Name = 'Height', 
           aa.Number_Value,
           NULL
         )) AS Article_Height,
         GROUP_CONCAT(IF(
           a.Attribute_Name = 'Description', 
           aa.Fulltext_Value,
           NULL
         )) AS Article_Description
FROM     Article_Attribute aa JOIN Attribute a USING (Attribute_ID)
GROUP BY aa.Article_ID

sqlfiddle上查看。

你能看到发生了什么吗?我们按文章分组 Article_Attribute表,然后使用GROUP_CONCAT()IF()操作的结果合并为NULL但是想要的记录。

我们可以使用我们选择的任何语言从Attribute表的内容动态生成这样的语句,并且您可能会发现在应用程序代码中这样做最容易(并且最容易理解)

恰好SQL本身也提供了the facility for generating and utilising dynamic statements,并且由于您没有说明您的应用程序是用什么语言开发的,我在下面展示了如何做到这一点:

SET group_concat_max_len = 4294967295; -- to overcome default 1KB limitation

SELECT CONCAT('
  SELECT   aa.Article_ID, ', GROUP_CONCAT('
             GROUP_CONCAT(IF(
               a.Attribute_Name = ', QUOTE(Attribute_Name), ', 
               aa.`', REPLACE(Data_type, '`', '``'), '_Value`,
               NULL
             )) AS `Article_', REPLACE(Attribute_Name, '`', '``'), '`
           ' SEPARATOR ','), '
  FROM     Article_Attribute aa JOIN Attribute a USING (Attribute_ID)
  GROUP BY aa.Article_ID
') INTO @sql FROM Attribute;

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

sqlfiddle上查看。

希望您能看到最终语句是如何从Attribute表格构建的(它是字符串,以红色突出显示),并且能够移植到您喜欢的任何语言。我引用并使用REPLACE()来转义恰好出现在属性或数据类型名称中的任何文字引号字符。

答案 1 :(得分:0)

我发现以下内容根据您提供的数据提供了所需的结果:

SELECT a1.ArticleID,MAX(Text_Value) AS Article_Name, MAX(Number_Value) AS Article_Height, MAX(Fulltext_Value) AS Article_Description
FROM Article_Attribute a1
GROUP BY ArticleID
;

我有点怀疑在这里使用MAX,因为它只能工作,因为NULL始终低于非null。我更喜欢像COALESCE这样的东西,但这不是一个聚合函数,因此给GROUP BY带来了不可靠的结果。