SQL maximum number of records with a common value - mysql

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

Related

How to get days missed in attendance table in mysql using NOT IN

I have a database for taking attendance daily.
every day is accounted for in a datetime (attended) field since there are never no students.
So, for a particular student ID (sid) I figure I'd be able to fill in the gaps of attendance using NOT IN.
select arrived, date_format(arrived,'%a') as 'day'
from attendance
where sid = '38'
and date_format(arrived, '%Y-%m-%d') NOT IN (
select DISTINCT date_format(arrived, '%Y-%m-%d')
from attendance
where MONTH(arrived) = 6
)
and MONTH(arrived) = 6
However, this generates the same results as if I hadn't used NOT IN at all. Now I'm realizing that those missing dates can't print because they're not in the sid limited query to begin with.
Can I move the NOT IN to the front of the query, so that the actual dates I want to display as absent are displayable.
For example, the student was absent 2019-06-06 (since that date is missing in 'his' query and other students were (so the nested query does show 2019-06-06)
See this fiddle: https://www.db-fiddle.com/f/x8VVvMBmizmsbJRHmY1GEd/0
select date(absences) absences from (select distinct date(arrived) absences from attendance) t2
where date(t2.absences) not in (select date(arrived) from attendance where sid=38)
You need to swap the inner and the outer query. You should look for attendance days of all students that are NOT IN attendance days of the specific student (sid=38):
select DISTINCT date(arrived) as 'day'
from attendance
where date(arrived) NOT IN (
select date(arrived)
from attendance
where sid = '38'
and MONTH(arrived) = 6
)
and MONTH(arrived) = 6

how to count number of lines with jointure in Talend on Oracle

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
;

SQL - only display either weekend or weekday price depending on date

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

MySQL right outer join query

I have a query regarding a query in MySQL.
I have 2 tables one containing SalesRep details like name, email, etc. I have another table with the sales data which has reportDate, customers served and link to the salesrep via a foreign key. One thing to note is that the reportDate is always a friday.
So the requirement is this: I need to find sales data for a 13 week period for a given list of sales reps - with 0 as customers served if on a particular friday there is no data. The query result is consumed by a Java application which relies on the 13 rows of data per sales rep.
I have created a table with all the Friday dates populated and wrote a outer join like below:
select * from (
select name, customersServed, reportDate
from Sales_Data salesData
join `SALES_REPRESENTATIVE` salesRep on salesRep.`employeeId` = salesData.`employeeId`
where employeeId = 1
) as result
right outer join fridays on fridays.datefield = reportDate
where fridays.datefield between '2014-10-01' and '2014-12-31'
order by datefield
Now my doubts:
Is there any way where i can get the name to be populated for all 13 rows in the above query?
If there are 2 sales reps, I'd like to use a IN clause and expect 26 rows in total - 13 rows per sales person (even if there is no record for that person, I'd still like to see 13 rows of nulls), and 39 for 3 sales reps
Can these be done in MySql and if so, can anyone point me in the right direction?
You must first select your lines (without customersServed) and then make an outer join for the customerServed
something like that:
select records.name, records.datefield, IFNULL(salesRep.customersServed,0)
from (
select employeeId, name, datefield
from `SALES_REPRESENTATIVE`, fridays
where fridays.datefield between '2014-10-01' and '2014-12-31'
and employeeId in (...)
) as records
left outer join `Sales_Data` salesData on (salesData.employeeId = records.employeeId and salesData.reportDate = records.datefield)
order by records.name, records.datefield
You'll have to do 2 level nesting, in your nested query change to outer join for salesrep, so you have atleast 1 record for each rep, then a join with fridays without any condition to have atleast 13 record for each rep, then final right outer join with condition (fridays.datefield = innerfriday.datefield and (reportDate is null or reportDate=innerfriday.datefield))
Very inefficient, try to do it in code except for very small data.

Exclude both rows one of them doesn't match criteria - self join?

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)