I've got a table that stores a person's tea preference on any given date. ;)
customer_id, tea_preference, date
1 'yes please' 2011-01-01
1 'no thanks' 2011-01-02
and I need to find customers that like tea within a given date range, eg:
SELECT * FROM customers
WHERE tea_preference = 'yes please'
AND date BETWEEN '2011-01-01' AND '2011-01-03'
Now, that query will give one match, but if the customer doesn't like tea on one of dates within the range, I don't want any matches for that customer...
I've tried self joins, but either they aren't the answer or I'm not doing it right, as I can't seem to get the result set I'm after. Help?!
Maybe:
SELECT c1.* FROM customers c1
WHERE c1.tea_preference = 'yes please'
AND c1.date BETWEEN '2011-01-01' AND '2011-01-03'
AND NOT EXISTS
(SELECT c2.* FROM customers c2
WHERE c2.tea_preference = 'no thanks'
AND c2.date BETWEEN '2011-01-01' AND '2011-01-03'
AND c1.custom_id = c2.customer_id)
Related
Question: Show the category of competitions that have always been hosted in the same country during May 2010. What is wrong with my query?
select Category
from competition
where Date >= '2010-01-01' and Date <= '2010-12-31'
group by Country, Category
having count(*) = (select count(*)
from competition
where Date >= '2010-01-01' and Date <= '2010-12-31'
group by Category)
You don't need two queries. Just use one query that checks that the count of countries is 1.
select category, count(DISTINCT country) AS country_count
from competition
where Date BETWEEN '2010-05-01' and '2010-05-31'
group by Category
HAVING country_count = 1
I also corrected the dates to be just May, not the whole year 2010.
Remove the GROUP BY if you that is making you return more than 1 row (in your HAVING CLAUSE. If you give me an example dataset and what you want I can help you more
I'd try something like this to start with:
SELECT COUNTRY
, CATEGORY
, COUNT(COUNTRY)
FROM COMPETITION
WHERE DATE BETWEEN '2010-04-30' AND '2010-06-01'
ORDER BY CATEGORY DESC, COUNT(COUNTRY) DESC
;
Your original query's date limits are just for the year of 2010 but you specified you only wanted May 2010. If the Date column is a date or datetime time you'll need to cast the string to the appropriate datatype.
Your question asked "always hosted by one country" - do you know that a competition is only going to be hosted by one country during that particular month? If you do, you're pretty much done. If you don't, however, then you need to clarify what your criteria really are
I am new to SQL (MySql) and I got stuck with this problem with one of my assignments and couldn't get answer from anyone or searching online about the subject. The question goes like:
Which bikes were live (is_live = TRUE) on December 8? (Display only bike_id).
Note: The Table does not have a row entry for December 8, and that is as intended
Name Type Description
id int LOG ID(PK)
bike_id int id of the bike
is_live boolean flag to indicate whether bike is live (TRUE/FALSE)
updated_on Date Date on which status of bike was updated
BIKE_LIVE_LOG table:
id bike_id is_live updated_on
1 1 TRUE 2018-12-01
2 2 TRUE 2018-12-01
3 3 TRUE 2018-12-01
4 3 FALSE 2018-12-02
5 2 FALSE 2018-12-05
6 3 TRUE 2018-12-10
I couldn't move forward with the question as I am not even getting the approach for it with my current knowledge.
I have used this query to generate the the last_update_date grouped by each bike_id.
select bll.bike_id, max(bll.updated_on) as last_update_date
from bike_live_log as bll
where bll.updated_on <= '2018-12-08'
group by bll.bike_id;
The output will be 1.
I'll try to help you get to the last step. You're really, really close!
You were correct in going down the road of finding the most recent updated_on date for each bike_id. It doesn't matter how many times a bike has been turned on or off; you really only care about the most recent status prior to the date you're interested in.
With your current query, you already know when each bike_id was last updated prior to December 8th.
Next, you can use that information to find out what the is_live value was for each of those bike_id values as of that last_update_date.
You can do that by using your existing query as a sub-query, or a CTE if you prefer, and join back to your main table again. Your JOIN criteria will be bike_id to bike_id and updated_on to last_update_date. By joining on the dates, you'll only return a single record for each bike_id, and that record will be the one you're interested in.
After you have your JOIN put together, you'll just need to add a WHERE clause to limit your result set to the rows where is_live = 'TRUE', which will return just bike_id of 1.
Your requirement can be expressed more data-centrically as find bikes whose last known status on or before Dec 8 was live.
This is one way (IMHO the most readable way) to express that in SQL:
select bike_id
from bike_live_log bll
where updated_on = (
select max(updated_on)
from bike_live_log
where bike_id = bll.bike_id
and updated_on <= '2018-12-08'
)
and is_live
The (corelated) subquery finds the date of the last update on or before Dec 8 for the current row of the outer query. If there's no such row, null will be returned, which won't match any rows from the outer query so, only bikes that have data on or before Dec 8 will be returned.
tl;dr
Here is the MySQL code you need:
SELECT bike_id FROM (
SELECT * FROM (
SELECT * FROM bikes
WHERE updated_on < '20181209'
ORDER BY updated_on DESC, id DESC
) AS sub
GROUP BY bike_id
) AS sub2
WHERE is_live = true
Why does this work?
We need to break down the question a little bit. I like to start from a position of "how can I get the information I need in a format that makes sense to me (as a human)?".
So the first thing I did was to get a list of all bikes with updated_on dates before the 9th Dec (i.e. were updated on the 8th Dec or before). I also ordered this by updated_on field so I (as a human) could easily see the "latest" record which will tell me the most recent status of each bike on or before the 8th Dec:
SELECT * FROM bikes
WHERE updated_on < '20181209'
ORDER BY updated_on DESC, id DESC
From this I can see there are 5 records of bike status changes before the 9th Dec. I can easily see that for each bike there are multiple "update" records, but I can now start from the top of the list and each bike id I encounter is the status on the 8th Dec.
Additionally I included an order_by for the record id. This is necessary because there could be multiple updates per day. The date itself won't tell us which of those updates was the latest ON THE SAME DAY, so we use the ID to determine that. (assuming it's chronologically incremental).
Now we have a list of all statuses and bike ids in the database before the 9th Dec we need to limit this to only one record per bike. This is easy, we can wrap the original query with a new query with a Group By directive on the bike_id.
SELECT * FROM (
SELECT * FROM bikes
WHERE updated_on < '20181209'
ORDER BY updated_on DESC, id DESC
) AS sub
GROUP BY bike_id
Group By in MySQL selects the first record it comes across for each group. We have already ordered the list by date and id in the original query, so the first record for each bike_id will be the latest status for that bike as of the 8th Dec.
Now, all that's left for us to do is to select the bike_id and filter out non-live bikes by using WHERE is_live = true on this latest query. That's how we end up with the query at the start of this answer:
SELECT bike_id FROM (
SELECT * FROM (
SELECT * FROM bikes
WHERE updated_on < '20181209'
ORDER BY updated_on DESC, id DESC
) AS sub
GROUP BY bike_id
) AS sub2
WHERE is_live = true
I hope this helps.
SELECT
bike_id,
MAX(CASE WHEN last_live_date <= '2018-12-08' AND ( last_not_live_date < last_live_date OR last_not_live_date IS NULL) THEN 1 ELSE 0 END) AS final_status
FROM
(
SELECT
bike_id,
MAX(CASE WHEN is_live = TRUE THEN updated_on END) AS last_live_date,
MAX(CASE WHEN is_live = FALSE THEN updated_on END) AS last_not_live_date
FROM `BIKE_LIVE_LOG`
WHERE updated_on <= '2018-12-08'
GROUP BY bike_id
) AS a
GROUP BY bike_id
HAVING final_status = 1;
with A as (select * from bike_live_log
where updated_on <= '2018-12-08'),
B as (select bike_id,max(updated_on) as updated from A
group by bike_id)
select A.bike_id from A inner join B
on A.updated_on = B.updated
where is_live = True;
i have 3 tables
supplier(id_supp, name, adress, ...)
Customer(id_cust, name, adress, ...)
Order(id_order, ref_cust, ref_supp, date_order...)
I want to make a job that counts the number of orders by Supplier, for last_week, last_two_weeks with Talend
select
supp.name,
(
select
count(*)
from
order
where
date_order between sysdate-7 and sysdate
nd ref_supp=id_supp
) as week_1,
(
select
count(*)
from
order
where
date_order between sysdate-14 and sysdate-7
nd ref_supp=id_supp
) as week_2
from supplier supp
the resaon for what i'm doing this, is that my query took to much time
You need a join between supplier and order to get supplier names. I show an inner join, but if you need ALL suppliers (even those with no orders in the order table) you may change it to a left outer join.
Other than that, you should only have to read the order table once and get all the info you need. Your query does more than one pass (read EXPLAIN PLAN for your query), which may be why it is taking too long.
NOTE: sysdate has a time-of-day component (and perhaps the date_order value does too); the way you wrote the query may or may not do exactly what you want it to do. You may have to surround sysdate by trunc().
select s.name,
count(case when o.date_order between sysdate - 7 and sysdate then 1 end)
as week_1,
count(case when o.date_order between sysdate - 14 and sysdate - 7 then 1 end)
as week_2
from supplier s inner join order o
on s.id_supp = o.ref_supp
;
I have a SQL statement returning information from the database about available dates.
SELECT *
FROM venue
WHERE NAME NOT IN (SELECT NAME
FROM venue_booking
WHERE date_booked = '2016-01-17')
AND capacity > 150
The table has two columns, weekday price and weekend price.
I only need to show one of them in the final output, depending on the date.
E.G. if date is during the week, display the weekday price of that venue.
From the MySQL Reference here:
DAYOFWEEK(date)
Returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 =
Saturday). These index values correspond to the ODBC standard.
You can use this function along with an IF or CASE to solve your problem.
SELECT `all_fields_other_than_price`,
CASE WHEN DAYOFWEEK('2016-01-17') IN (1,7) THEN v.weekend_price
ELSE v.weekday_price
END AS `VENUE_PRICE`
FROM venue v
WHERE name NOT IN(
SELECT name FROM venue_booking WHERE date_booked = '2016-01-17')
AND capacity > 150;
Do you mean something like this ?
SELECT *, IF(dayofweek(NOW()) = 7, v.weekday_price, v.weekend_price) as final_price FROM venue v
WHERE name NOT IN(SELECT name FROM venue_booking WHERE date_booked = '2016-01-17')
AND capacity > 150
NOTE
Change number 7 in IF(dayofweek(NOW()) = 7 to your desired day number.
Use this query:
Select CASE when DAYOFWEEK(booked_date)>1 and
DAYOFWEEK(booked_date)< 7 then weekday_price
ELSE weekend_price
END as price
From venue
WHERE NAME NOT IN (SELECT NAME FROM venue_booking WHERE date_booked = '2016-01-17') AND capacity > 150
Repeating the same date more than one time in a query can be dangerous (in terms of keeping the query consistent). In addition, I am not a fan of NOT IN, because it doesn't behave intuitively with NULL values.
So, you might consider:
SELECT v.*,
(CASE WHEN dayofweek(thedate) IN (1, 7) then weekend_price
ELSE weekday_price
END) as price
FROM (SELECT date('2016-01-17') as thedate) params CROSS JOIN
venue v LEFT JOIN
venue_booking vb
ON v.name = vb.name AND vb.date_booked = thedate
WHERE vb.name IS NULL AND
v.capacity > 150
Please consider the following two tables:
Holidays
HolidayID (PK)
Destination
Length
MaximumNumber
...
Bookings
BookingID (PK)
HolidayID (FK)
Name
...
Customers can book holidays (e.g. go to Hawaii). But, suppose that a given holiday has a maximum number of places. e.g. there are only 75 holidays to Hawaii this year (ignoring other years).
So if some customer wants to book a holiday to Hawaii. I need to count the records in Bookings table, and if that number is greater than 75 I have to tell the customer it's too late.
This I can do using 2 MySQL queries (1 to get MaximumNumber for the holiday, 2 to get the current total from Bookings) and PHP (for example) to compare the count value with the maximum number of Hawaii holidays.
But I want to know if there is a way to do this purely in SQL (MySQL in this case)? i.e. count the number of bookings for Hawaii and compare against Hawaii's MaximumNumber value.
EDIT:
My method:
$query1 = "SELECT MaximumNumber FROM Holidays WHERE HolidayID=$hawaiiID";
$query2 = "SELECT COUNT(BookingID) FROM Bookings WHERE HolidayID=$hawaiiID";
So if the first query gives 75 and the second query gives 75 I can compare these values in PHP. But I wondered if there was a way to do this somehow in SQL alone.
Maybe I am missing something, but why not use a subquery to determine the total bookings for each holidayid:
select *
from holidays h
left join
(
select count(*) TotalBooked, HolidayId
from bookings
group by holidayId
) b
on h.holidayId = b.holidayId
WHERE h.HolidayID=$hawaiiID;
See SQL Fiddle with Demo.
Then you could use a CASE expression to compare the TotalBooked to the MaxNumber similar to this:
select h.destination,
case
when b.totalbooked = h.maxNumber
then 'Not Available'
else 'You can still book' end Availability
from holidays h
left join
(
select count(*) TotalBooked, HolidayId
from bookings
group by holidayId
) b
on h.holidayId = b.holidayId
WHERE h.HolidayID=$hawaiiID;
See SQL Fiddle with Demo.
You will notice that I used a LEFT JOIN which will return all rows from the Holidays table even if there are not matching rows in the Bookings table.
Something like this will work. You can fill in the details:
select case
when
(select count(*)
from Bookings
where holidayID = $hawaiiid)
<= MaximumNumber then 'available' else 'sold out' end status
from holidays
etc
You might try something like this:
select case when b.freq < h.MaximumNumber
then 'Available'
else 'Not Available'
end as MyResult
from Holidays h
left join (
select HolidayID
, count(*) as freq
from Bookings
where HolidayID=$hawaiiID
group by HolidayID
) b
on h.HolidayID=b.HolidayID