Select new or returning items for a specified year

◇◆丶佛笑我妖孽 提交于 2019-12-23 03:38:12

问题


I have a table which looks roughly like this:

+---------------------+----------+
| date                | item     |
+---------------------+----------+
| 2008-11-30 11:15:59 | Plums    |
| 2012-11-08 19:42:37 | Lemons   |
| 2013-01-30 18:58:07 | Apples   |
| 2013-02-12 13:44:45 | Pears    |
| 2014-06-08 11:46:48 | Apples   |
| 2014-09-01 20:28:03 | Oranges  |
+---------------------+----------+

I would now like to select items for two cases:

1) I'd like to select all distinct items for this year (or a different specified year) which are NEW this year, meaning that they have not appeared in previous years. This query should therefore give me "Oranges" as a result for 2014.

2) I'd also like to select all distinct items for this (or another specified) year which are RETURNING, which obviously means that they have appeared in previous years. This query should give me "Apples" as a result for 2014.

To clarify, I would like to use both queries only for comparison to previous years. So if I were to specify 2013 as the year for which this query is run, "Apples" should appear as new, not returning.

I don't necessarily need both things in one query (I doubt it's possible), so two different queries, one for each case, are perfectly fine.


回答1:


How about (SQL Fiddle) for NEW items:

SELECT DISTINCT m1.item
FROM MyTable m1
  LEFT JOIN MyTable m2 ON m1.item = m2.item AND YEAR(m2.date) < 2014
WHERE YEAR(m1.date) = 2014
  AND m2.date IS NULL

And (SQL Fiddle) for RETURNING items:

SELECT DISTINCT m1.item
FROM MyTable m1
  INNER JOIN MyTable m2 ON m1.item = m2.item
WHERE YEAR(m1.date) = 2014
  AND YEAR(m2.date) < 2014

If you want to combine the two queries together (SQL Fiddle or SQL Fiddle):

SELECT DISTINCT m1.item, 'New' AS Status
FROM MyTable m1
  LEFT JOIN MyTable m2 ON m1.item = m2.item AND YEAR(m2.date) < 2014
WHERE YEAR(m1.date) = 2014
  AND m2.date IS NULL
UNION ALL
SELECT DISTINCT m1.item, 'Returning' AS Status
FROM MyTable m1
  INNER JOIN MyTable m2 ON m1.item = m2.item
WHERE YEAR(m1.date) = 2014
  AND YEAR(m2.date) < 2014
ORDER BY Status;



回答2:


1 - This solution can use an index

SELECT DISTINCT x.item 
  FROM my_table x 
  LEFT 
  JOIN my_table y 
    ON y.item = x.item 
   AND y.date < x.date 
 WHERE x.date BETWEEN '2014-01-01' AND '2014-12-31' AND y.date IS NULL;

2 - And so can this...

SELECT DISTINCT x.item 
  FROM my_table x 
  JOIN my_table y 
    ON y.item = x.item 
   AND y.date < x.date 
 WHERE x.date BETWEEN '2014-01-01' AND '2014-12-31';

2 is obviously a simpler problem than 1, so I'm a little surprised you've asked for them in this order !?!?

If you remove the WHERE ... IS NULL from the first query then you in effect get the answer which you 'doubt is possible', but a UNION of these two queries will achieve the same effect.




回答3:


this will give you fruits that are in a specific year but not in other years

SELECT t.item 
FROM table t 
WHERE YEAR(t.date) = 2014 
  AND NOT EXISTS (SELECT 1 FROM table f WHERE YEAR(f.date) <> 2014 AND f.item = t.item)

this will give you ones that are in more than one year

SELECT t.item 
FROM table t 
WHERE YEAR(t.date) = 2014 
  AND EXISTS (SELECT 1 FROM table f WHERE YEAR(f.date) <> 2014 AND f.item = t.item)

you can put them all into one like this.

SELECT t.item as "NEW", f.item as 'RETURNING'
FROM
(   SELECT t.item, @a := (COALESCE(@a, 0) + 1) as join_col 
    FROM test t 
    WHERE YEAR(t.date) = 2014 
      AND NOT EXISTS (SELECT 1 FROM test f WHERE YEAR(f.date) <> 2014 AND f.item = t.item)
) t
LEFT JOIN
(   SELECT t.item , @b := (COALESCE(@b, 0) + 1) as join_col 
    FROM test t 
    WHERE YEAR(t.date) = 2014 
      AND EXISTS (SELECT 1 FROM test f WHERE YEAR(f.date) <> 2014 AND f.item = t.item)
) f ON f.join_col = t.join_col;

DEMO



来源:https://stackoverflow.com/questions/25853891/select-new-or-returning-items-for-a-specified-year

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!