如何从具有条件的重复日期行中仅选择一行

时间:2016-05-25 11:20:59

标签: mysql

我有一个看起来像下面提到的结果集,我从下面提到的查询中得到了结果:

LEAVE_DATE  | RESOURCE_ID | TYPE
2016-05-17 |    1         | SELF
2016-05-27 |    1         | SELF
2016-05-30 |    0         | ORG
2016-05-30 |    1         | SELF

以下是给出上述结果集的SQL:

SELECT CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8) LEAVE_DATE, v.RESOURCE_ID, v.TYPE
FROM date_tbl t,tbl_leave v
WHERE t.n <= DATEDIFF(v.END_DATE, v.START_DATE) + 1
AND RESOURCE_ID IN (1,0)
AND DAYOFWEEK(CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8)) NOT IN (1,7)
ORDER BY LEAVE_DATE

我希望我的SQL应该返回所有唯一日期,但如果找到RESOURCE_ID 0和1的重复日期,我想选择RESOURCE_ID 0。

预期结果:

LEAVE_DATE  | RESOURCE_ID | TYPE
2016-05-17 |    1         | SELF
2016-05-27 |    1         | SELF
2016-05-30 |    0         | ORG

请您提出一些建议,我应该如何实现这一结果?

3 个答案:

答案 0 :(得分:0)

首先,您选择获取所有值,然后按resource_id对其进行排序,然后通过leave_date对结果进行分组。 group by将获得第一行重复。

SELECT * FROM 
(
SELECT CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8) LEAVE_DATE, v.RESOURCE_ID, v.TYPE
FROM date_tbl t,tbl_leave v
WHERE t.n <= DATEDIFF(v.END_DATE, v.START_DATE) + 1
AND RESOURCE_ID IN (1,0)
AND DAYOFWEEK(CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8)) NOT IN (1,7)
ORDER BY v.RESOURCE_ID
)as x GROUP BY x.LEAVE_DATE

答案 1 :(得分:0)

假设您每个日期只需要一条记录,那么我能看到的唯一安全方法是添加序列号(按leave_date排序,然后是resource_id),并且只返回每个日期的第一条记录。

未通过以下方式测试: -

SELECT LEAVE_DATE,
        RESOURCE_ID,
        TYPE
FROM
(
    SELECT LEAVE_DATE,
            RESOURCE_ID,
            TYPE,
            if(@prev_leave_date=LEAVE_DATE, @cnt + 1, 1) AS cnt,
            @prev_leave_date:=LEAVE_DATE
    FROM
    (
        SELECT CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8) LEAVE_DATE, 
                v.RESOURCE_ID, 
                v.TYPE
        FROM date_tbl t
        INNER JOIN tbl_leave v
        ON  t.n <= DATEDIFF(v.END_DATE, v.START_DATE) + 1
        WHERE RESOURCE_ID IN (1,0)
        AND DAYOFWEEK(CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8)) NOT IN (1,7)
        ORDER BY LEAVE_DATE, RESOURCE_ID
    ) sub0
    CROSS JOIN
    (
        SELECT @prev_leave_date:="", @cnt:=0
    ) sub1
) sub2
WHERE cnt = 1

避免使用子查询的另一个选项是滥用GROUP_CONCAT。获取每一行,按LEAVE_DATE分组并在resource_id上​​使用GROUP_CONCAT并键入以获取每个LEAVE DATE的每个值的所有值。按resource_id排序,以便首先获得resource_id为0的那些。默认情况下,GROUP_CONCAT值由逗号分隔,因此使用SUBSTRING_INDEX从每个值中获取第一个值(请注意,如果resource_id或类型可以包含逗号,则需要指定不同的分隔符并将结果拆分)

未经过测试(没有表格声明或测试数据),但是这样: -

    SELECT CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8) LEAVE_DATE, 
            SUBSTRING_INDEX(GROUP_CONCAT(v.RESOURCE_ID ORDER BY v.RESOURCE_ID), ',', 1) AS RESOURCE_ID, 
            SUBSTRING_INDEX(GROUP_CONCAT(v.TYPE ORDER BY v.RESOURCE_ID), ',', 1) AS TYPE
    FROM date_tbl t
    INNER JOIN tbl_leave v
    ON  t.n <= DATEDIFF(v.END_DATE, v.START_DATE) + 1
    WHERE RESOURCE_ID IN (1,0)
    AND DAYOFWEEK(CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8)) NOT IN (1,7)
    GROUP BY LEAVE_DATE
    ORDER BY LEAVE_DATE, RESOURCE_ID

答案 2 :(得分:0)

这是一个愚蠢的答案,但作为您对问题和评论的描述,这可能是一个简单的答案。

SELECT LEAVE_DATE, IF(COUNT(1) > 1, 0, RESOURCE_ID) AS RESOURCE_ID, IF(COUNT(1) > 1, 'ORG', `TYPE`) AS `TYPE`
FROM(
    SELECT CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8) LEAVE_DATE, v.RESOURCE_ID, v.`TYPE`
    FROM date_tbl t,tbl_leave v
    WHERE t.n <= DATEDIFF(v.END_DATE, v.START_DATE) + 1
    AND RESOURCE_ID IN (1,0)
    AND DAYOFWEEK(CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8)) NOT IN (1,7)
    ORDER BY LEAVE_DATE)
GROUP BY LEAVE_DATE

<强>编辑:

SELECT
    CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8) LEAVE_DATE,
    IF(COUNT(1) > 1, 0,v.RESOURCE_ID) AS RESOURCE_ID,
    IF(COUNT(1) > 1, 'ORG', v.`TYPE`) AS `TYPE`
FROM date_tbl t,tbl_leave v
WHERE t.n <= DATEDIFF(v.END_DATE, v.START_DATE) + 1
-- AND RESOURCE_ID IN (1,0) -- This is what you want to remove!!!
AND DAYOFWEEK(CONVERT(v.START_DATE + INTERVAL t.n - 1 DAY USING utf8)) NOT IN (1,7)
ORDER BY LEAVE_DATE
GROUP BY LEAVE_DATE
相关问题