SQL如何让sql返回一行而不是每个不同的ID多个?

时间:2017-11-17 23:02:35

标签: sql

根据我的同事的说法,我们正在使用IBM DB2

我真的很难让我的sql每个ID返回一行。在工作中被问到但是这里没有女孩对SQL很好......我可以做一些SQL但不是SQL专家。

为了更好地解释,我设置了以下示例

这是TABLE及其数据

ID  DATE        CODE  PERCENT
01  2016-08-21  1111  52
01  2016-09-06  1111  60
01  2016-10-06  1112  38
02  2016-05-01  6666  50
02  2016-10-01  1111  50

我希望每个ID最早返回一条记录。 所以我在下面写了SQL

SELECT ID, MIN(DATE) 
FROM TABLE
WHERE DATE >= '2016-01-01' AND  DATE <= '2017-11-01'
AND   CODE = 1111
GROUP BY ID

工作得很好。我会得到

01 2016-08-21
02 2016-10-01

我很快意识到我还需要PERCENT专栏。

SELECT ID, MIN(DATE), PERCENT
FROM TABLE
WHERE DATE >= '2016-01-01' AND  DATE <= '2017-11-01'
AND   CODE = 1111
GROUP BY ID, PERCENT

但现在,我为ID 01获取了多行,这是错误的......

01  2016-08-21  1111  52
01  2016-09-06  1111  60
02  2016-10-01  1111  50

有人可以帮我修复这个SQL或者指向正确的方向,这样我每个ID就可以有一行,如下所示吗?

01  2016-08-21  1111  52
02  2016-10-01  1111  50

7 个答案:

答案 0 :(得分:1)

GROUP BY ID将执行必要的操作,无需GROUP BY百分比。如果您是GROUP BY百分比,则会添加一个新行,因为它具有不同的值。

SELECT ID, MIN(DATE), code, percent
FROM table
WHERE DATE BETWEEN '2016-01-01' AND '2017-11-01'
AND   CODE = 1111
GROUP BY ID;

希望这有帮助。

答案 1 :(得分:1)

IF 您的数据库支持row_number() over(),然后使用该功能是确定哪些行是最早的&#34;最早的&#34;像这样:

select *
from (
       select *
          , row_number() over(partition by ID, CODE order by DATE ASC) as is_oldest
       from YOURTABLE
       where DATE >= '2016-01-01' AND  DATE <= '2017-11-01'
       and CODE = 1111
     ) d
where is_oldest = 1

这样做的显着优点是它可以访问与&#34;最老的&#34;相关的整行。无需加入。

注意这种方法的灵活性,它可以很容易地扩展,例如

select *
from (
       select *
          , row_number() over(partition by ID, CODE order by date ASC) as is_oldest
          , row_number() over(partition by ID, CODE order by date DESC) as is_recent
       from your_table
       WHERE DATE >= '2016-01-01' AND  DATE <= '2017-11-01'
       AND   CODE = 1111
     ) d
where is_oldest = 1
or is_recent = 1

所有人都必须做到最近的&#34;是将顺序从ASCending更改为DESCending。

注意:v8之前的MySQL不支持&#34;窗口函数,例如row_number,但是计划在v8之后。许多其他数据库都支持此功能。

答案 2 :(得分:0)

SELECT
    Earliest.ID,
    Earliest.Date,
    TABLE.PERCENT
FROM (
    SELECT 
        ID, 
        MIN(DATE)
    FROM
        TABLE
    WHERE 
        DATE BETWEEN '2016-01-01' AND  '2017-11-01'
        AND CODE = 1111
    GROUP BY ID
) AS Earliest
INNER JOIN TABLE ON Earliest.ID = Table.ID

解释为什么您的调整后的查询返回多个记录:百分比列具有不同的数据,因此当您按其分组时,它将为每个更改添加新记录。

在这个答案中,您可以通过加入汇总结果从基础表中获得百分比。

答案 3 :(得分:0)

如果这是SQL Server,您可以使用TOP 1 WITH TIESORDER BY

SELECT TOP 1 WITH TIES ID, DATE, PERCENT
FROM TABLE
WHERE DATE >= '2016-01-01' AND  DATE <= '2017-11-01'
AND  CODE = 1111
ORDER BY ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DATE ASC)

答案 4 :(得分:0)

不要按PERCENT分组,只按ID分组。在select语句中添加代码。

select id, min(date), code, percent
from tablename
where date between '2016-01-01' AND  '2017-11-01'
and   code = 1111
group by id;

答案 5 :(得分:0)

我假设您正在使用MS SQL Server。您可以使用所谓的CTE(使用cluse)来获取最小日期,然后将其加入主表:see the working example on sql fiddle

-- first find the min date for each ID
with min_date as (
SELECT ID, MIN(DATE) [DATE]
FROM tbl
WHERE DATE >= '2016-01-01' AND  DATE <= '2017-11-01'
AND   CODE = 1111
GROUP BY ID
)

-- join it to the table and get the result
select t.ID, md.[DATE], t.[PERCENT]
from tbl t
inner join min_date as md
on md.ID = t.ID and md.[DATE] = t.[date]

答案 6 :(得分:0)

PERCENT击败群组的原因是因为PERCENT在行之间有所不同,而您正在使用GROUP BY 删除重复项。 PERCENT使行不同...您可以改为子查询从表中重新获取具有相同ID和MIN(DATE)的行

SELECT dT.ID
      ,dT.DATE
      ,(SELECT T.PERCENT
          FROM TABLE T
         WHERE T.ID = dT.ID AND T.DATE = dT.DATE
       ) AS Percent
  FROM (
         SELECT ID, MIN(DATE) AS DATE
           FROM TABLE
          WHERE DATE >= '2016-01-01' AND  DATE <= '2017-11-01'
            AND   CODE = 1111
         GROUP BY ID
       ) AS dT