1

releases在 SQLite3 数据库中有这张表,列出了应用程序的每个发布版本:

|release_id|release_date|app_id|
|==========|============|======|
|      1001| 2009-01-01 |     1|
|      1003| 2009-01-01 |     1|
|      1004| 2009-02-02 |     2|
|      1005| 2009-01-15 |     1|

所以对于每个 app_id,都会有多行。我有另一张桌子,apps

|app_id|name    |
|======|========|
|     1|Everest |
|     2|Fuji    |

我想显示应用程序的名称和最新版本,其中“最新”表示 (a) 最新 release_date,如果有重复,(b) 最高 release_id。

我可以为单个应用程序执行此操作:

SELECT apps.name,releases.release_id,releases.release_date 
  FROM apps 
  INNER JOIN releases 
    ON apps.app_id = releases.app_id
  WHERE releases.release_id = 1003
  ORDER BY releases.release_date,releases.release_id
  LIMIT 1

但当然 ORDER BY 适用于整个 SELECT 查询,如果我省略 WHERE 子句,它仍然只返回一行。

这是对小型数据库的一次性查询,因此慢速查询、临时表等都很好——我只是想不通用 SQL 的方式来做这件事。

4

5 回答 5

1

使用分析函数 ROW_NUMBER() 很容易做到这一点,我猜 sqlite3 不支持。但是您可以采用比先前答案中给出的更灵活的方式来做到这一点:

SELECT
  apps.name,
  releases.release_id,
  releases.release_date 
FROM apps INNER JOIN releases 
ON apps.app_id = releases.app_id
WHERE NOT EXISTS (
-- // where there doesn't exist a more recent release for the same app
  SELECT * FROM releases AS R
  WHERE R.app_id = apps.app_id
  AND R.release_data > releases.release_data
)

例如,如果您有多个定义“最新”的排序列,则 MAX 对您不起作用,但您可以修改 EXISTS 子查询以捕获“最新”的更复杂含义。

于 2009-09-10T01:26:13.970 回答
1

这是“每组最大 N”问题。它每周在 StackOverflow 上出现几次。

我通常使用像@Steve Kass' answer中的解决方案,但我没有子查询(几年前我养成了 MySQL 4.0 的习惯,它不支持子查询):

SELECT a.name, r1.release_id, r1.release_date
FROM apps a
INNER JOIN releases r1
LEFT OUTER JOIN releases r2 ON (r1.app_id = r2.app_id 
  AND (r1.release_date < r2.release_date
    OR r1.release_date = r2.release_date AND r1.release_id < r2.release_id))
WHERE r2.release_id IS NULL;

在内部,这可能与NOT EXISTS语法相同地优化。您可以分析查询EXPLAIN以确保。


关于您的评论,您可以跳过测试,release_date因为release_id对于确定发布的时间顺序同样有用,并且我认为它保证是唯一的,因此这简化了查询:

SELECT a.name, r1.release_id, r1.release_date
FROM apps a
INNER JOIN releases r1
LEFT OUTER JOIN releases r2 ON (r1.app_id = r2.app_id 
  AND r1.release_id < r2.release_id)
WHERE r2.release_id IS NULL;
于 2009-09-10T01:34:42.173 回答
0

这很丑,但我认为它会工作

select apps.name, (select releases.release_id from releases where releases.app_id=apps.app_id order by releases.release_date, releases.release_id), (select releases.release_date from releases where releases.app_id=apps.app_id order by releases.release_date, releases.release_id) from apps order by apps.app_id

我希望有某种方法可以将这两列都放在一个嵌入式选择中,但我不知道。

于 2009-09-10T01:04:22.080 回答
0

尝试:

SELECT a.name,
       t.max_release_id,
       t.max_date
  FROM APPS a
  JOIN (SELECT t.app_id,
               MAX(t.release_id) 'max_release_id',
               t.max_date
          FROM (SELECT r.app_id,
                       r.release_id,
                       MAX(r.release_date) 'max_date'
                  FROM RELEASES r
              GROUP BY r.app_id, r.release_id)
      GROUP BY t.app_id, t.max_date) t
于 2009-09-10T01:07:10.453 回答
0

错误的第二次尝试。假设 ID 单调递增并且不太可能发生溢出,您可以忽略日期并执行以下操作:

SELECT apps.name, releases.release_id, releases.release_date 
FROM apps INNER JOIN releases on apps.app_id = releases.app_id
WHERE releases.release_id IN 
(SELECT Max(release_id) FROM releases
GROUP BY app_id);
于 2009-09-10T04:56:03.050 回答