如何按列分组

3

你好,我知道如何使用SQL的group by子句。但我不确定该如何解释它,所以我画了一些图表。这是我的原始数据:

Name          Location
----------------------
user1         1
user1         9
user1         3
user2         1
user2         10
user3         97

这是我需要的输出

Name          Location
----------------------
user1         1
              9
              3
user2         1
              10
user3         97

这真的有可能吗?


6
你想要的是一种美化数据展示的方式。但这并不是 SQL 的作用。 - user554546
我正在做这件事是为了提交给管理层的报告。 - Luke101
是的,这是可能的。请查看SQL Cookbook,它告诉您如何实现此操作。警告:复杂。 - Matt Fenwick
1
@Luke101 不要直接从 SQL 输出。最好使用 Excel 或类似的工具,这些工具可以轻松地将 SQL 作为数据源。 - JNK
然后将报告以Excel格式呈现给他们,或者添加其他层次来美化数据。这不是关系型数据库管理系统的用途。 - user554546
7个回答

4
这种情况通常需要在表示层中处理,而不是数据库层。
原因如下:
  • Name字段是该数据行的属性
  • 如果您将Name留空,如何知道哪个位置与哪个名称相对应?
  • 您隐含地依赖于数据的顺序,在SQL中这是一种非常糟糕的做法(因为返回的数据没有固有的顺序)
  • 任何解决方案都需要涉及游标或循环,这不是SQL所优化的——它喜欢在集合上工作,而不是在单个行上

3
希望这有所帮助。


SELECT A.FINAL_NAME, A.LOCATION
  FROM (SELECT DISTINCT DECODE((LAG(YT.NAME, 1) OVER(ORDER BY YT.NAME)),
                               YT.NAME,
                               NULL,
                               YT.NAME) AS FINAL_NAME,
                        YT.NAME,
                        YT.LOCATION
          FROM YOUR_TABLE_7 YT) A

As Jirka correctly pointed out, I was using the Outer select, distinct and raw Name unnecessarily. My mistake was that as I used DISTINCT , I got the resulted sorted like


1           1
2   user2   1
3   user3   97
4   user1   1
5           3
6           9
7          10

我希望避免这样的输出。

因此,我添加了原始ID和外部选择器。

然而,删除DISTINCT就可以解决问题。因此只需要这么多。


SELECT DECODE((LAG(YT.NAME, 1) OVER(ORDER BY YT.NAME)),
              YT.NAME,
              NULL,
              YT.NAME) AS FINAL_NAME,
       YT.LOCATION
  FROM SO_BUFFER_TABLE_7 YT

感谢Jirka。

我完全忘记了窗口函数。 - Luke101
很好。为什么不从选择列表中删除外部的SELECT,内部的DISTINCT和原始的YT.NAME?我期望会得到相同的结果。 - Jirka Hanika

2

如果您使用纯 SQL*Plus 制作报告(别笑,它还是有些很酷的功能的),您可以使用 BREAK 命令 来完成此操作:

SQL> break on name
SQL> WITH q AS (
SELECT 'user1' NAME, 1 LOCATION FROM dual
UNION ALL
SELECT 'user1', 9 FROM dual
UNION ALL
SELECT 'user1', 3 FROM dual
UNION ALL
SELECT 'user2', 1 FROM dual
UNION ALL
SELECT 'user2', 10 FROM dual
UNION ALL
SELECT 'user3', 97 FROM dual
)
SELECT NAME,LOCATION
  FROM q
 ORDER BY name;

NAME    LOCATION
----- ----------
user1          1
               9
               3
user2          1
              10
user3         97

6 rows selected.

SQL>

1
如果您使用GROUP BY,输出行将按照GROUP BY列进行排序,就像您对相同列使用ORDER BY一样。为了避免GROUP BY产生的排序开销,请添加ORDER BY NULL
SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;

依赖于MySQL 5.6中隐式GROUP BY排序已被弃用。为了实现对分组结果的特定排序顺序,最好使用显式ORDER BY子句。GROUP BY排序是MySQL的扩展,可能会在未来的版本中更改;例如,使优化器能够以其认为最有效的方式对分组进行排序,并避免排序开销。
有关完整信息 - http://academy.comingweek.com/sql-groupby-clause/

1

如果您正在使用SQL*Plus,请使用BREAK函数。在这种情况下,按NAME中断。

如果您使用另一个报表工具,则可以将“名称”字段与上一条记录进行比较,并在它们相等时抑制打印。


1
我不得不同意其他评论者的观点,这种问题似乎不应该使用SQL解决,但无论如何我们还是要面对它。
SELECT
    CASE main.name WHERE preceding_id IS NULL THEN main.name ELSE null END,
    main.location
FROM mytable main LEFT JOIN mytable preceding
    ON main.name = preceding.name AND MIN(preceding.id) < main.id
GROUP BY main.id, main.name, main.location, preceding.name
ORDER BY main.id

GROUP BY子句并不直接负责分组工作。在第一次近似中,可以使用与同一表的外连接(下面是LEFT JOIN)来确定特定值首次出现的行。这就是我们想要的。这假设存在一些唯一的id值,使得可以任意排序所有记录。(ORDER BY子句不会这样做;它对输出进行排序,而不是整个计算的输入,但仍然需要确保输出正确呈现,因为剩余的SQL没有暗示任何特定的处理顺序。)

正如您所看到的,SQL中仍然有一个GROUP BY子句,但其目的可能出乎意料。它的工作是“撤消”LEFT JOIN的副作用,即重复所有具有许多“前导”(=成功连接)记录的主记录。

这在GROUP BY中非常正常。GROUP BY子句的典型效果是减少记录数;无法通过聚合函数(如COUNT、MIN、MAX或SUM)以外的方式查询或测试未列在GROUP BY子句中的列。这是因为这些列实际上代表由GROUP BY产生的“值组”,而不仅仅是特定值。


谢谢!我必须稍微调整一下查询,但现在它可以工作了。感谢您指导我走向正确的方向。 - Luke101

0

SQL GROUP BY语句 SQL GROUP BY子句与SELECT语句一起使用,将相同的数据分组排列。 语法: 1. SELECT column_nm,aggregate_function(column_nm) FROM table_nm WHERE column_nm operator value GROUP BY column_nm; 示例: 为了理解GROUP BY子句,请参考样例数据库。下表显示了“order”表中的字段: 1. | EMPORD_ID | employee1ID | customerID | shippers_ID |

下表显示了“shipper”表中的字段: 1. | shippers_ID | shippers_Name |

下表显示了“table_emp1”表中的字段: 1. | employee1ID | first1_nm | last1_nm |

示例: 查找每个承运人发送的订单数量。 1. SELECT shipper.shippers_Name, COUNT(orders.EMPORD_ID) AS No_of_orders FROM orders LEFT JOIN shipper ON orders.shippers_ID = shipper.shippers_ID GROUP BY shippers_Name; 1. | 承运人名称 | 订单数量 | 示例: 在多个列上使用GROUP BY语句。 1. SELECT shipper.shippers_Name, table_emp1.last1_nm, COUNT(orders.EMPORD_ID) AS No_of_orders FROM ((orders INNER JOIN shipper ON orders.shippers_ID=shipper.shippers_ID) INNER JOIN table_emp1 ON orders.employee1ID = table_emp1.employee1ID) 2. GROUP BY shippers_Name,last1_nm;

  1. | 承运人名称 | 姓氏 | 订单数量 |

要了解更多详细信息,请参考我的链接 http://academy.comingweek.com/sql-groupby-clause/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接