【问题标题】:Select a predefined maximum value选择一个预定义的最大值
【发布时间】:2021-11-25 17:19:14
【问题描述】:

我有一张表格,里面有我的用户数据。

Id Name VersionId
1 Name A 1
2 Name B 2
3 Name C 1
4 Name A 2
5 Name E 1
6 Name F 3
7 Name G 2
8 Name C 4
9 Name A 5

还有第二个表格,其中我代表了每个用户所在的版本:

Id Version
1 1.2
2 1.3
3 1.4
4 1.5
5 1.6

我在编写查询以返回当前版本为 1.3 的用户时遇到问题。如果用户在某个时候已经拥有 1.3 版,但目前已不在其中,则不应选择此值。 随着时间的推移,用户可以转换多个版本。在查询中,我只想要当前使用 1.3 版的用户。也就是说,只有 ID 为 2 和 7 的用户。

【问题讨论】:

  • 第二个表中的一个用户可以有多行?
  • 你真的想要最大值还是想要每个用户的最后一个值?
  • @OlivierJacot-Descombes 随着时间的推移,用户可以转换多个版本。在查询中,我只想要当前使用 1.3 版的用户。也就是说,只有 ID 为 2 和 7 的用户。名为“名称 A”的用户曾在 1.3 版中的某一时刻,但目前其版本为 1.6,因此不应返回。
  • 这些是字符串还是数字?
  • 嗯,它不能是整数,但我想你的意思是小数。

标签: sql-server select max


【解决方案1】:

您可以将 MAX 与分区一起使用。这里我假设如果用户的版本高于 1.3,那么该用户已经使用 1.3,因此 WHERE 子句只能返回 1.3 的用户。

DROP TABLE IF EXISTS #userdata;
CREATE TABLE dbo.#userdata(
  [Id] INT,
  [Name] VARCHAR(100),
  [VersionId] INT
);
GO

INSERT INTO dbo.#userdata ([Id],[Name],[VersionId])
SELECT 1, 'Name A', 1 UNION ALL
SELECT 2, 'Name B', 2 UNION ALL
SELECT 3, 'Name C', 1 UNION ALL
SELECT 4, 'Name A', 2 UNION ALL
SELECT 5, 'Name E', 1 UNION ALL
SELECT 6, 'Name F', 3 UNION ALL
SELECT 7, 'Name G', 2 UNION ALL
SELECT 8, 'Name C', 4 UNION ALL
SELECT 9, 'Name A', 5;


DROP TABLE IF EXISTS #versiondata;
CREATE TABLE dbo.#versiondata(
  [Id] INT,
  [Version] DECIMAL(18, 6)
);
GO

INSERT INTO dbo.#versiondata ([Id],[Version])
SELECT 1, 1.2 UNION ALL
SELECT 2, 1.3 UNION ALL
SELECT 3, 1.4 UNION ALL
SELECT 4, 1.5 UNION ALL
SELECT 5, 1.6;

WITH mx AS (
    SELECT DISTINCT
        u.Name,
        MAX(v.Version) OVER (PARTITION BY u.Name) Version
    FROM #userdata u
    INNER JOIN #versiondata v ON v.id = u.VersionId
)
SELECT mx.Name, mx.Version
FROM mx
WHERE mx.Version = 1.3;

【讨论】:

  • 我怀疑 userdata 表是一个历史表,并且 OP 希望每个用户最后一次出现,即实际值。
  • @OlivierJacot-Descombes 我明白你在说什么。我仍然认为这适用于我从问题中解释的内容,只是添加了 WHERE 子句以限制到 v1.3(以及我添加到答案中的假设)。
  • @squillman 是的,它是一个用户版本控制表。对于新功能,我只需要当前使用 1.3 版的用户。如果它们在某个时候是 1.3,那没关系,因为我只想要当前的。
  • @LSantos 好的,很好。那么这应该提供你正在寻找的东西。这将返回当前处于 1.3 的任何人。
  • @squillman 执行脚本时,它返回(名称 A、名称 B、名称 G)。 "B" 和 "G" 好的,毕竟它们是在 1.3 版本中。但是“A”是 1.6 版本,“A”曾经是 1.3,但现在已经不是了。
【解决方案2】:

从子查询开始,为每个用户查找“最新”版本。在这种情况下,“最新”被定义为每个用户具有最大 id 值的行。

                  SELECT MAX(Id) Id
                    FROM usertable 
                   GROUP BY Name

然后使用子查询从用户表中获取您需要的行,加入您的版本表,并使用适当的 WHERE 子句。

SELECT versiontable.Version, usertable.Name
  FROM versiontable
  JOIN usertable on versiontable.Id = usertable.VersionId
  JOIN ( 
                     SELECT MAX(Id) Id
                       FROM usertable 
                      GROUP BY Name
       ) m ON usertable.Id = m.Id
 WHERE Version = '1.3'

Fiddle here.

【讨论】:

    【解决方案3】:

    您可以像这样使用窗口函数返回每个用户的最后一个条目

    SELECT
        x.Id, x.Name
    FROM (SELECT
              Id,
              Name,
              VersionId,
              ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Id DESC) AS rowNum
          FROM UserData) x
          INNER JOIN VersionData v
              ON x.VersionId = v.Id
    WHERE
        x.rowNum = 1 AND
        v.Version = '1.3'
    

    即使用户降级到以前的版本,这仍然有效。

    返回

    Id Name
    2 Name B
    7 Name G

    见:http://sqlfiddle.com/#!18/93a572/15/0

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-05
      • 1970-01-01
      • 2021-05-28
      • 2012-05-29
      • 1970-01-01
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      相关资源
      最近更新 更多