Mysql select ordinal

92dk7w1h  于 2023-10-15  发布在  Mysql
关注(0)|答案(3)|浏览(90)

有一个名为books的表,它具有以下结构:

╔════════════╦═══════════╦════════╗
║ LibraryId  ║  BookId   ║ Price  ║
╠════════════╬═══════════╬════════╣
║ 123        ║ 9001      ║ 10.99  ║
║ 123        ║ 9005      ║ 12.99  ║
║ 123        ║ 9006      ║ 7.99   ║
║ 124        ║ 8012      ║ 6.49   ║
║ 124        ║ 9001      ║ 3.19   ║
║ 124        ║ 9076      ║ 7.39   ║
╚════════════╩═══════════╩════════╝

我怎样才能执行一个返回完整表的选择,但另外还有一个名为Ordinal的字段,用于“计算”每个图书馆的图书数量。结果应该如下所示:

╔════════════╦═══════════╦════════╦════════╗
║ LibraryId  ║  BookId   ║ Price  ║Ordinal ║
╠════════════╬═══════════╬════════╬════════╣
║ 123        ║ 9001      ║ 10.99  ║      1 ║
║ 123        ║ 9005      ║ 12.99  ║      2 ║
║ 123        ║ 9006      ║ 7.99   ║      3 ║
║ 124        ║ 8012      ║ 6.49   ║      1 ║
║ 124        ║ 9001      ║ 3.19   ║      2 ║
║ 124        ║ 9076      ║ 7.39   ║      3 ║
╚════════════╩═══════════╩════════╝════════╝

我试过这样的东西:

SET @var_record = 1;
SELECT *, (@var_record := @var_record + 1) AS Ordinal
FROM books;

但无论libraryId如何,这都将继续计数。我需要的东西,将重置序号每次libraryId的变化。我更喜欢一个单一的查询,而不是程序。
测试数据SQL脚本:

create temporary table books(libraryId int, bookId int, price double(4,2));
insert into books (libraryId, bookId, price) values (123, 9001, 10.99),(123, 9005, 10.99),(123, 9006, 10.99),(124, 8001, 10.99),(124, 9001, 10.99),(124, 9076, 10.99);
px9o7tmv

px9o7tmv1#

使用变量和条件,您可以根据条件(libraryId已更改)重置计数器。必须按列libraryId排序。

SELECT books.*, 
    if( @libId = libraryId, 
        @var_record := @var_record + 1, 
        if(@var_record := 1 and @libId := libraryId, @var_record, @var_record)
    ) AS Ordinal 
FROM books
JOIN (SELECT @var_record := 0, @libId := 0) tmp
ORDER BY libraryId;

第二个if语句用于将两个赋值组合在一起并返回@var_record。

if(@var_record := 1 and @libId := libraryId, @var_record, @var_record)
gojuced7

gojuced72#

这显然是一个非常古老的问题,但它仍然被谷歌发现,所以这里有一个现代的答案,任何人谁来到这里寻找如何根据结果集的哪个子部分(分区)来识别行。

SELECT *
     , ROW_NUMBER() OVER (PARTITION BY column_0) AS ordinal
FROM (
VALUES
  ROW(123, 9001, 10.99)
, ROW(123, 9005, 12.99)
, ROW(123, 9006, 7.99)
, ROW(124, 8012, 6.49)
, ROW(124, 9001, 3.19)
, ROW(124, 9076, 7.39)
) AS t
;

+--------+--------+--------+-------+
|column_0|column_1|column_2|ordinal|
+--------+--------+--------+-------+
|123     |9001    |10.99   |1      |
|123     |9005    |12.99   |2      |
|123     |9006    |7.99    |3      |
|124     |8012    |6.49    |1      |
|124     |9001    |3.19    |2      |
|124     |9076    |7.39    |3      |
+--------+--------+--------+-------+

恕我直言,任何来自旧版本MySQL并经常使用数据库的人都应该熟悉窗口函数(https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html),因为它们释放了巨大的潜力。
顺便说一句,如果你只是想计算每个图书馆的图书数量,

SELECT column_0
     , COUNT(*) AS book_count
FROM ...
GROUP BY 1
;
iszxjhcz

iszxjhcz3#

也许你可以使用聚合函数

SELECT a.LibraryId, a.BookId, a.Price,
      (SELECT COUNT(b.BookId) FROM books b WHERE b.BookId = a.BookId AND b.LibraryId = a.LibraryId) AS Ordinal
FROM a.books

相关问题