【问题标题】:Group By same or similar string sql按相同或相似的字符串sql分组
【发布时间】:2016-12-14 07:11:05
【问题描述】:

1)假设我有一张这样的桌子:-

| id    |  color_code  |      fruit      |
|:------|--------------|----------------:|
| 1     |  000001      |      apple      |     
| 2     |  000001      |      apple      |    
| 3     |  000001      |      apple      |      
| 4     |  000002      |      lemon      |         
| 5     |  000002      |      lemon      |       
| 6     |  000003      |      grapes     |
| 7     |  000003      |      grapes     | 

如何根据sql server中的color_code列水果列分组?

我想是这样的:-

| id    |  color_code  |      fruit      |   group_concat(id)  |
|:------|--------------|-----------------|---------------------|
| 1     |  000001      |      apple      |        1,2,3        |
| 4     |  000002      |      lemon      |        2,5          |
| 6     |  000003      |      grapes     |        6,7          |

2) 如果我有 3 个需要连接的表(如下所示),我该如何实现呢?

series_no 表:

|   id  |  desc_seriesno  |
|:------|----------------:|
| 7040  |     AU1011      |
| 7041  |     AU1022      |
| 7042  |     AU1033      |
| 7043  |     AU1044      |
| 7044  |     AU1055      |
| 7045  |     AU1066      |

品牌表:

|   id  |  desc_brand     |
|:------|----------------:|
| 1020  |     Audi        |
| 1021  |     Bentley     |
| 1022  |     Ford        |
| 1023  |     BMW         |
| 1024  |     Mazda       |
| 1025  |     Toyota      |

car_info 表:

|   seriesno_id  |  brand_id  |  color  |
|:---------------|------------|--------:|
|     7040       |    1020    | white   |
|     7040       |    1020    | black   |
|     7040       |    1020    | pink    |
|     7041       |    1021    | yellow  |
|     7041       |    1021    | brown   |
|     7042       |    1022    | purple  |
|     7042       |    1022    | black   |
|     7042       |    1022    | green   |
|     7043       |    1023    | blue    |
|     7044       |    1024    | red     |
|     7045       |    1025    | maroon  |
|     7045       |    1025    | white   |    

这是我当前使用 sql server 2014 的查询:-

SELECT SN.id AS seriesid, B.id AS brandid, B.desc_brand
FROM [db1].[dbo].[series_no] SN
  LEFT JOIN [db1].[dbo].[car_info] CI
  ON CI.seriesno_id = SN.id
  RIGHT JOIN [db1].[dbo].[brand] B
  ON B.id = CI.brand_id
GROUP BY SN.id, B.id
ORDER BY SN.id ASC

但不幸的是,它给了我一个错误,因为我不能以这种方式按类似的字符串分组。

我希望它是这样的:-

|  seriesid  |   brandid  |   desc_brand  | count |
|:-----------|------------|---------------|-------|
|    7040    |    1020    |     Audi      |   3   |
|    7041    |    1021    |     Bentley   |   2   |
|    7042    |    1022    |     Ford      |   3   |
|    7043    |    1023    |     BMW       |   1   |
|    7044    |    1024    |     Mazda     |   1   |
|    7045    |    1025    |     Toyota    |   2   |

【问题讨论】:

    标签: sql-server string group-by equals


    【解决方案1】:

    1 水果色

    假设表名是FruitColor,可以通过如下查询得到想要的输出-

    SELECT MIN(id) AS id
        , color_code
        , fruit
        , group_concat_id = STUFF((SELECT ',' + CAST(id AS VARCHAR)
                                   FROM FruitColor AS fci
                                   WHERE fci.fruit = fc.fruit AND fci.color_code = fc.color_code
                                   FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
    FROM FruitColor AS fc
    GROUP BY color_code, fruit
    ORDER BY id;
    

    2。为此,您可以有多种选择 -

    选项 (a):显示品牌系列的计数

    SELECT seriesno_id AS seriesid, ci.brand_id AS bandid, desc_brand, COUNT(*)    AS [count]
    FROM db1.dbo.car_info AS ci
    LEFT JOIN db1.dbo.brand AS b ON (b.id = ci.brand_id)
    GROUP BY seriesno_id, ci.brand_id, desc_brand;
    
    • 如果要显示具有品牌的汽车的计数,则无需在此处使用系列表。
    • 您可能不需要在品牌表上使用 RIGHT JOIN,因为如果品牌表包含一条记录 不在 car_info 表中,则 seriesno_id 将为空。

    选项 (b):显示所有带有或不带有品牌的系列的计数

    SELECT sn.id AS seriesid, ci.brand_id AS bandid, desc_brand, COUNT(*) AS [count]
    FROM db1.dbo.series_no AS sn
    LEFT JOIN db1.dbo.car_info AS ci ON (ci.seriesno_id = sn.id)
    LEFT JOIN db1.dbo.brand AS b ON (b.id = ci.brand_id)
    GROUP BY sn.id, ci.brand_id, desc_brand;
    

    选项 (c):选择不在 GROUP BY 中的列的解决方法

    SELECT seriesno_id AS seriesid, ci.brand_id AS bandid, MAX(desc_brand) AS desc_brand, COUNT(*) AS [count]
    FROM db1.dbo.car_info AS ci
    LEFT JOIN db1.dbo.brand AS b ON (b.id = ci.brand_id)
    GROUP BY seriesno_id, ci.brand_id;
    
    • 在这里,如果我们确定每个品牌只包含一个 desc_brand,我们可以对其使用聚合。 这是因为仅应用聚合一个值会返回该值。我在这里使用了 MAX。

    我个人会选择选项 (a),因为它更有意义。

    关于 desc_brand 为 NTEXT 的 GROUP BY 异常更新...

    将 desc_brand 强制转换为 NVARCHAR 以避免异常。

     CAST(desc_brand AS NVARCHAR(200))
    

    另外我强烈建议使用 VARCHAR / NVARCHAR 代替任何 TEXT、CHAR 等,因为它们通常占用更多内存。

    【讨论】:

    • 如果我有 3 个需要加入的表怎么办?我该如何应用这种方法?您可以参考下面我回答的问题。
    • 我已经添加了第二个答案。告诉我进展如何。
    • 它有效!顺便说一句,我更改了第二个问题的答案 a) 如此处link 中所述,因为我的 desc_brand 声明为 ntext,这将给出错误“文本、ntext 和图像数据类型无法比较或排序,除非使用 IS NULL 或 LIKE运算符”,如果只是按原样运行。
    • 我已经更新了 desc_brand 解决方法的答案。但是,强制转换可能会导致性能下降,因此您应该几乎总是在列声明中使用 VARCHAR 或 NVARCHAR。
    【解决方案2】:
    SELECT 
    id = SUBSTRING(group_concat,1,1),
    color_code,
    fruit,
    group_concat
    FROM(
    SELECT distinct
       m.color_code, 
       m.fruit,       
       group_concat = STUFF((SELECT ',' + CONVERT(varchar(10),md.id) 
                             FROM [Test_1].[dbo].[Stuff] md
                             WHERE m.fruit = md.fruit 
                                AND m.color_code = md.color_code 
                             FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
    FROM [Test_1].[dbo].[Stuff] m)x
    

    【讨论】:

      【解决方案3】:

      使用下面的代码..

      SELECT distinct
             m.color_code
           , m.fruit      
           , group_concat = STUFF((
                SELECT ',' + CONVERT(varchar(10),md.id) 
                FROM dbo.tablename md
                WHERE m.fruit = md.fruit and m.color_code = md.color_code 
                FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
      FROM dbo.tablename  m
      

      第二次:

      SELECT SN.id AS seriesid, B.id AS brandid, B.desc_brand ,count(*)
      FROM [db1].[dbo].[series_no] SN
        LEFT JOIN [db1].[dbo].[car_info] CI
        ON CI.seriesno_id = SN.id
        RIGHT JOIN [db1].[dbo].[brand] B
        ON B.id = CI.brand_id
      GROUP BY SN.id, B.id ,B.desc_brand
      ORDER BY 4 ASC
      

      【讨论】:

      • 如果要加入多个表,我该如何实现?请在我发布的答案部分中参考下面的问题。
      • 您能推荐任何我可以查看的参考资料吗? @sandeep rawat,顺便说一句,我刚刚编辑了我的帖子,你能帮我吗?
      • 但实际上两者都是不同的问题,您不应该尝试混合完全不相关的问题,因为这个问题成为用户(正在寻找相同问题)的相对参考。
      • 好的,请注意!我的错。仍在尝试解决堆栈溢出问题。顺便说一句,谢谢你的回答。
      猜你喜欢
      • 2017-02-25
      • 2018-11-20
      • 1970-01-01
      • 1970-01-01
      • 2019-10-25
      • 2019-03-03
      • 2012-01-27
      • 2018-06-11
      • 1970-01-01
      相关资源
      最近更新 更多