简体   繁体   中英

SQL Query: Retrieve rows that have an entry for every unique value of a column

Background:

I have performed a price search at three different times for different objects. These searches are saved in a table with their corresponding search time, object name, and price.

I would like to compare the price of objects over time, but I only want to pull objects that have prices, or were available, during all three searches.

Said another way, I want to query all prices over time by product, but only if that product has a price for all time periods (and I do not know how many time periods there are in advance--this must be determined from the table dynamically).

My plan is to use SQL for this (first time trying SQL...Maybe it is inappropriate for this task?)

Example data:

+----------+----------+----------+----------+
| Time     | Item     | Price    | Dummy    |
+----------+----------+----------+----------+
| 1:00 PM  | Toy      | 100      | 1        |
| 1:00 PM  | Cola     | 200      | 2        |
| 1:00 PM  | Book     | 300      | 3        |
| 2:00 PM  | Toy      | 100      | 4        |
| 2:00 PM  | Book     | 250      | 5        |
| 3:00 PM  | Toy      | 100      | 6        |
| 3:00 PM  | Cola     | 250      | 7        |
| 3:00 PM  | Book     | 200      | 8        |
+----------+----------+----------+----------+

Goal result:

+----------+----------+----------+----------+
| Item     | 1:00 PM  | 2:00 PM  | 3:00 PM  |
+----------+----------+----------+----------+
| Toy      | 100      | 100      | 100      |
| Book     | 300      | 250      | 200      |
+----------+----------+----------+----------+

(Cola is excluded because it didn't exist when searched for at 2:00 PM)

I put the data into an SQLfiddle here: http://www.sqlfiddle.com/#!2/61046/1

Any insight is welcome! Thanks!

Is MySQL a requirement? In PostgreSQL (or Oracle or other DBMSs) I would use something like this:

WITH better_format as (
  SELECT  a.Item, a.Time, a.Price, count(*) over ( partition by a.Item ) as distinct_times
  FROM    tableName a
  GROUP BY a.Item, a.Time, a.Price
)
SELECT * FROM better_format
WHERE distinct_times = (
  SELECT max(distinct_times) from better_format
)

Your desired output is a pivot of this. Oracle and PostgreSQL have Pivot and Crosstab features to return exactly what you want. I'm not aware of MySQL having the analogous abilities.

SQL Fiddle

A SQL query has to return a fixed number of columns, known in advance. You cannot vary the number of columns depending on the number of times in the data.

You can come close, by concatenating the prices together. Then, you want to keep rows where there is a price for every time. This uses a having clause to count the number of prices and compare to the number of time values in the table:

select item, group_concat(price order by time) as prices
from tablename
group by item
having count(price) = (select count(distinct time) from tablename)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM