【问题标题】:sql group by one column and then filter on one column and create new columns for different valuessql 按一列分组,然后过滤一列并为不同的值创建新列
【发布时间】:2013-04-05 16:52:21
【问题描述】:

在 MS Access 查询中,如何对一列进行分组,然后使用最大 ID 从表中获取特定值。我知道我可以分组并使用 max 来获取最大 ID,但不知道如何获取多个最大 ID。

如果我有这样的表:

+----+------+-------+------+
| ID | Col1 | Col2  | Col3 |
+----+------+-------+------+
|  1 | a    | one   |  100 |
|  2 | a    | two   |  200 |
|  3 | a    | three |  300 |
|  4 | a    | four  |  400 |
|  5 | a    | five  |  500 |
|  6 | b    | one   |  600 |
|  7 | b    | two   |  700 |
|  8 | b    | three |  800 |
|  9 | b    | four  |  900 |
| 10 | b    | one   | 1000 |
| 11 | b    | three | 1100 |
| 12 | b    | six   | 1200 |
| 13 | c    | one   | 1300 |
| 14 | c    | two   | 1400 |
| 15 | c    | three | 1500 |
| 16 | c    | four  | 1600 |
| 17 | c    | six   | 1700 |
| 18 | c    | three | 1800 |
| 19 | c    | two   | 1900 |
| 20 | c    | one   | 2000 |
+----+------+-------+------+

我想得到这个:

+------+------+------+-------+
| Col1 | one  | two  | three |
+------+------+------+-------+
| a    |  100 |  200 |   300 |
| b    | 1000 |  700 |  1100 |
| c    | 2000 | 1900 |  1800 |
+------+------+------+-------+

当 Col1 = b 且 Col2 = 1 时,ID = 6 和 10。由于 10 较大,因此该行的值是 1000。对于表的其余部分也是如此...

我这辈子都不知道该怎么做。

【问题讨论】:

  • 欢迎来到 Stack Overflow!请通过添加适当的标记(Oracle、SQL Server、MySQL 等)来指定您要定位的 RDBMS。可能有一些答案利用了不受普遍支持的语言或产品功能。此外,通过使用特定的 RDBMS 对其进行标记,您的问题可能会受到更适合回答的人的关注。

标签: sql ms-access ms-access-2007 pivot


【解决方案1】:

这将返回您在 Access 2007 中使用示例数据请求的结果。

SELECT
    sub.Col1,
    DLookup('Col3', 'YourTable', 'ID=' & sub.MaxOfID1) AS [one],
    DLookup('Col3', 'YourTable', 'ID=' & sub.MaxOfID2) AS [two],
    DLookup('Col3', 'YourTable', 'ID=' & sub.MaxOfID3) AS [three]
FROM
    (
        SELECT
            y.Col1,
            Max(IIf(y.Col2='one', y.ID, 0)) AS MaxOfID1,
            Max(IIf(y.Col2='two', y.ID, 0)) AS MaxOfID2,
            Max(IIf(y.Col2='three', y.ID, 0)) AS MaxOfID3
        FROM YourTable AS y
        GROUP BY y.Col1
    ) AS sub;

【讨论】:

    【解决方案2】:

    由于您没有提及您的 RDBMS,因此几乎所有 RDBMS 都支持以下查询。

    SELECT  Col1,
            MAX(CASE WHEN Col2 = 'one' THEN Col3 END) one,
            MAX(CASE WHEN Col2 = 'two' THEN Col3 END) two,
            MAX(CASE WHEN Col2 = 'three' THEN Col3 END) three
    FROM    TableName
    GROUP   BY Col1
    

    输出

    ╔══════╦══════╦══════╦═══════╗
    ║ COL1 ║ ONE  ║ TWO  ║ THREE ║
    ╠══════╬══════╬══════╬═══════╣
    ║ a    ║  100 ║  200 ║   300 ║
    ║ b    ║ 1000 ║  700 ║  1100 ║
    ║ c    ║ 2000 ║ 1900 ║  1800 ║
    ╚══════╩══════╩══════╩═══════╝
    

    【讨论】:

    • MS 访问。我犯了一个错误。 Col3 中的#s 并不总是更大,因此不能在该列上使用 max。必须找到具有 MAX 的行 ID,然后获取该行的列值...
    【解决方案3】:
    select col1, 
        max(case col2 when 'one' then col3 else 0 end) as One,
        max(case col2 when 'two' then col3 else 0 end) as Two,
        max(case col2 when 'three' then col3 else 0 end) as three
    from MyTable
    group by col1
    

    【讨论】:

      【解决方案4】:

      这适用于 MS-Access:

      TRANSFORM Max(tbl.Col3) AS MaxDiCol3
      SELECT tbl.Col1
      FROM tbl
      WHERE (((tbl.Col2)="one" Or (tbl.Col2)="two" Or (tbl.Col2)="three"))
      GROUP BY tbl.Col1
      PIVOT tbl.Col2;
      

      如果您需要获取最大 ID,而不是最大值,我建议您使用它来代替:

      TRANSFORM Max(tbl.ID) AS MaxDiCol3
      SELECT tbl.Col1
      FROM tbl
      WHERE (((tbl.Col2)="one" Or (tbl.Col2)="two" Or (tbl.Col2)="three"))
      GROUP BY tbl.Col1
      PIVOT tbl.Col2;
      

      并将其保存为查询,例如Query1。然后,您可以通过以下方式获取实际值:

      SELECT
        Query1.Col1,
        tbl.Col3 AS one,
        tbl_1.Col3 AS two,
        tbl_2.Col3 AS three
      FROM
        ((Query1 LEFT JOIN tbl ON Query1.one = tbl.ID)
        LEFT JOIN tbl AS tbl_1 ON Query1.two = tbl_1.ID)
        LEFT JOIN tbl AS tbl_2 ON Query1.three = tbl_2.ID;
      

      【讨论】:

        【解决方案5】:

        我认为你需要Dynamic PIVOT and Group By

        SQL FIDDLE DEMO

        
        declare @cols varchar(max)
        declare @query varchar(max)
        DECLARE @selective nvarchar(max)
        
        SELECT @selective =
          STUFF((SELECT ',MAX(' + QUOTENAME(t.col2) +') as ' + QUOTENAME(t.col2)  AS ColName    
                 from (
                 select distinct  col2                            
                 FROM yourtable
                 )  t                     
                 FOR XML PATH( ''), TYPE).value ('.', 'nvarchar(max)'),1,1,'')
        
        select @cols = STUFF((SELECT ',' + QUOTENAME(t.col2)  AS ColName   
                 from (
                 select distinct  col2                            
                 FROM yourtable
                 )  t                 
                 FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'),1,1,'')
        
        set @query = ' ;with CTE_PivotTable
                       as
                       (
                       select ID, Col1, ' + @cols + 
                     ' from 
                            ( select ID, Col1, Col2, Col3 
                              from yourtable
                            ) t
                            pivot
                               (
                                  max(col3) for col2 in ('+@Cols+')
                                ) as P
                        )
                        select Col1, ' + @selective + 
                        'from CTE_PivotTable
                         group by Col1'
        
        exec(@query)    
        

        输出结果

        
        
        COL1 | FIVE  |  FOUR  |  ONE  |  SIX  |  THREE  | TWO
        -----------------------------------------------------
        a    | 500   |  400   |  100  | (null)|  300    | 200 
        b    | (null)|  900   |  1000 | 1200  |  1100   | 700 
        c    |(null) |  1600  |  2000 | 1700  |  1800   |1900 
        

        【讨论】:

        • 为什么人们在不留下理由的情况下投反对票?怎么了?告诉我,我很乐意学习。
        【解决方案6】:

        试试这个:

        SELECT 
          t1. col1, 
          MAX(CASE WHEN t1.col2 = 'one' THEN t1.col3 END) AS 'one',
          MAX(CASE WHEN t1.col2 = 'two' THEN t1.col3 END) AS 'two',
          MAX(CASE WHEN t1.col2 = 'three' THEN t1.col3 END) AS 'three'
        FROM tablename AS t1
        INNER JOIN
        (
          SELECT col1, MAX(ID) AS MAXID
          FROM tablename
          WHERE col2 IN('one', 'two', 'three')
          GROUP BY col1, col2
        ) AS t2 ON t1.col1 = t2.col1 AND t1.id = t2.maxid
        GROUP BY t1.col1;
        

        带有子查询的JOIN 只会为您提供每个col1col2 的最大ID 值。

        SQL Fiddle Demo

        这会给你:

        | COL1 |  ONE |  TWO | THREE |
        ------------------------------
        |    a |  100 |  200 |   300 |
        |    b | 1000 |  700 |  1100 |
        |    c | 2000 | 1900 |  1800 |
        

        罢工>

        但是:如果您使用支持窗口函数和PIVOT 表运算符的RDBMS,例如SQL Server,您可以这样做:

        WITH CTE 
        AS
        (
          SELECT *,
            ROW_NUMBER() OVER(PARTITION BY col1, col2
                              ORDER BY ID) AS RN
          FROM tablename
          WHERE col2 IN('one', 'two', 'three')
        )
        SELECT *
        FROM
        (
          SELECT col1, col2, col3
          FROM CTE
          WHERE RN <= 3
        ) AS t
        PIVOT
        (
          MAX(col3)
          FOR col2 IN([one], [two], [three])
        ) AS p;
        

        Updated SQL Fiddle Demo

        【讨论】:

        • 是的。看起来是这样。现在玩它。非常感谢!
        • @Nacho - 随时欢迎您 :) 尝试accept 答案,如果它以您想要的方式正常工作并且您发现它有帮助。
        猜你喜欢
        • 1970-01-01
        • 2020-12-20
        • 2015-08-10
        • 1970-01-01
        • 2013-05-26
        • 2023-02-06
        • 2014-06-17
        • 1970-01-01
        • 2019-04-06
        相关资源
        最近更新 更多