using two cases of exists in sql query - mysql

I am trying to make a query that says If the customer has no invoice, but has an appointment in the last 6 months, please give me their clientId and name The following result returns and empty set.
SELECT clients.clientId, clients.studentFirstName, clients.studentLastName
FROM clients, invoices, appointments
WHERE (NOT EXISTS
(SELECT *
FROM invoices, clients
WHERE invoices.clientId = clients.clientId))
AND (EXISTS
(SELECT * FROM appointments, clients
WHERE appointments.clientId = invoices.clientId
AND appointments.date >= DATE_ADD(curdate(), INTERVAL 6 MONTH)));
EDIT: The query that ended up working was created after a little tweaking of john's answer:
SELECT a.clientID,
a.studentFirstName,
a.studentLastName
FROM clients a
LEFT JOIN invoices b
on a.clientID = b.clientID
LEFT JOIN appointments c
on a.clientID = c.clientID
WHERE b.clientId IS NULL AND
c.`date` >= DATE_SUB(curdate(), INTERVAL 6 MONTH)

Use LEFT JOIN instead.
SELECT a.ClientID,
a.studentFirstName,
a.clients.studentLastName
FROM clients a
LEFT JOIN invoices b
on a.ClientID = b.ClientID
LEFT JOIN appointments c
on a.ClientID = c.ClientID
WHERE b.Client IS NULL AND
c.`Date` >= DATE_SUB(curdate(), INTERVAL 6 MONTH)

Are you sure it's supposed to be DATE_ADD and not DATE_SUB ?
You can use joins:
SELECT a.clientId,
a.studentFirstName,
a.studentLastName
FROM clients a
JOIN appointments b ON a.clientId = b.clientId
AND b.date >= CURDATE() - INTERVAL 6 MONTH
LEFT JOIN invoices c ON a.clientId = c.clientId
WHERE c.clientId IS NULL

Related

how do i add up on sql so it doesn't double because group by

when i'm running my program, the results of the number instead make a number merge and make the number into many results.
SELECT pengiriman_supply.po_nomor
, data_supplier.nama_supplier
, data_barang.nama_barang,
((sum(pengiriman_supply.jumlah))-(ifnull(masuk.terima,0))) as total
FROM pengiriman_supply INNER JOIN data_supplier ON pengiriman_supply.idsupplier = data_supplier.id_supplier
INNER JOIN data_barang ON pengiriman_supply.idbarang = data_barang.idbarang
left JOIN masuk on masuk.refrence = pengiriman_supply.po_nomor
where pengiriman_supply.tanggal between date_sub(curdate(), interval 120 day) and curdate()
group by pengiriman_supply.po_nomor
ORDER BY pengiriman_supply.po_nomor desc;
the results is this
enter image description here
Seems you are trying to get the sum() per po number. lets put this in a subquery then join again those tables you want info to show.
select t.po_nomor
, p.nama_supplier
, p1.nama_barangfrom
, t.total
from
(select t1.po_nomor
, (sum(t1.jumlah)-coalesce(t4.terima,0)) as total
from pengiriman_supply t1
inner join data_supplier t2 on t1.idsupplier = t2.id_supplier
inner join data_barang t3 on t1.idbarang = t3.idbarang
left join masuk t4 on t4.refrence = t1.po_nomor
where t1.tanggal between date_sub(curdate(), interval 120 day) and curdate()
group by t1.po_nomor) t
inner join pengiriman_supply s on s.po_nomor = t.po_nomor
inner join data_supplier p on s.idsupplier = p.id_supplier
inner join data_barang p1 on t.idbarang = p1.idbarang
order by t.po_nomor desc;

Combine two conditions with diffrent tables MySQL

Can I make one query with this two conditions? And if yes, which way should I dig?
SELECT c.ID, c.DateEnd FROM conference c WHERE DateEnd = DATE_ADD(CURDATE(),INTERVAL 1 DAY)
SELECT a.ID, a.IDConf FROM application a GROUP BY a.IDConf HAVING COUNT(a.IDConf) >= 2
if you want join only the result for HAVING COUNT(a.IDConf) >= 2 you could use a inner join on subselect
SELECT c.ID, c.DateEnd
FROM conference c
INNER JOIN (
SELECT a.ID, a.IDConf
FROM application a
GROUP BY a.IDConf
HAVING COUNT(a.IDConf) >= 2
) t ON c.ID=t.IDConf
WHERE c.DateEnd = DATE_ADD(CURDATE(),INTERVAL 1 DAY)
You can use a left join. Try this:
SELECT c.ID, a.ID a_ID, c.DateEnd
FROM conference c LEFT JOIN application a
ON c.ID=a.IDConf
WHERE DateEnd=DATE(DATE_ADD(CURDATE(),INTERVAL 1 DAY))
GROUP BY c.ID, a.ID
HAVING COUNT(a.IDConf)>=2;
See MySQL Join Made Easy for insight on using joins.

MySQL subquery in select

I have the following scenario. i have three tables (users, sales, sales_details) Users to Sales is a 1 to 1 relationship and sales to sales_details is 1 to many.
I am running a query where I get all the sales for each user by joining all 3 tables without any issue.
Query looks something like this
SELECT s.month as month,u.name as name, s.year as year, s.date as date,sum(sd.qty) as qty,sum(sd.qty*sd.value) as value,s.id as id,sum(sd.stock) as stock,s.currency as currency,s.user as user
FROM sales as s
left join sales_details as sd on s.id = sd.Sales
inner join users as u on s.user = u.Id
group by s.Id
What I want to do now is add an extra field in my query which will be a subquery.
SELECT SUM(total) AS total_yearly
FROM (
SELECT sum(qty) as total
FROM sales
left join sales_details on sales.Id = sales_details.Sales
WHERE ((month <= MONTH(NOW()) and year = YEAR(NOW()))
or (month >= MONTH(Date_add(Now(),interval - 12 month)) and year = YEAR(Date_add(Now(),interval - 12 month))))
and User = **ID OF USER** ) as sub
This query on its own gives me the sales for the user for the past 12 months while the original query does it per month. I know that the result will be the same for each user but i need it for other calculations.
My problem is how I will join the 2 queries so that the subquery will read the user id from the original one.
Thanks in advance!
Group the second query by user, and then join it with the original query.
SELECT s.month as month,u.name as name, s.year as year, s.date as date,
sum(sd.qty) as qty,sum(sd.qty*sd.value) as value,s.id as id,
sum(sd.stock) as stock,s.currency as currency,s.user as user,
us.total
FROM sales as s
left join sales_details as sd on s.id = sd.Sales
inner join users as u on s.user = u.Id
inner join (
SELECT User, sum(qty) as total
FROM sales
left join sales_details on sales.Id = sales_details.Sales
WHERE ((month <= MONTH(NOW()) and year = YEAR(NOW()))
or (month >= MONTH(Date_add(Now(),interval - 12 month)) and year = YEAR(Date_add(Now(),interval - 12 month)))))
GROUP BY User) AS us ON s.user = us.user
group by s.Id

MySQL count() within subquery

I am trying to count the number of bookings for the next 7 days with the following query.
select calendarDate,
(
select COUNT(*)
FROM isBooked INNER JOIN booking
ON isbooked.BookingID = booking.bookingID
where specificday between booking.startDate and booking.endDate
)
from calendar as specificday
where calendardate between '2015-08-23' and DATE_ADD('2015-08-23', INTERVAL 6 DAY);
I have used SQL server which allows the use of 'as specificday' however MySQL does not, how would i rewrite the query in mysql.
specificday refers to a table, not a column. You need a column name for the WHERE clause:
select c.calendarDate,
(select COUNT(*)
from isBooked ib INNER JOIN
booking b
ON ib.BookingID = b.bookingID
where c.calendarDate between b.startDate and b.endDate
)
from calendar c
where c.calendardate between '2015-08-23' and DATE_ADD('2015-08-23', INTERVAL 6 DAY);

finding closest date from multiple tables mysql

I have many tables that log the users action on some forum, each log event has it's date.
I need a query that gives me all the users that wasn't active in during the last year.
I have the following query (working query):
SELECT *
FROM (questions AS q
INNER JOIN Answers AS a
INNER JOIN bestAnswerByPoll AS p
INNER JOIN answerThumbRank AS t
INNER JOIN notes AS n
INNER JOIN interestingQuestion AS i ON q.user_id = a.user_id
AND a.user_id = p.user_id
AND p.user_id = t.user_id
AND t.user_id = n.user_id
AND n.user_id = i.user_id)
WHERE DATEDIFF(CURDATE(),q.date)>365
AND DATEDIFF(CURDATE(),a.date)>365
AND DATEDIFF(CURDATE(),p.date)>365
AND DATEDIFF(CURDATE(),t.date)>365
AND DATEDIFF(CURDATE(),n.date)>365
AND DATEDIFF(CURDATE(),i.date)>365
what i'm doing in that query - joining all the tables according to the userId, and then checking each
date column individually to see if it's been more then a year
I was wondering if there is a way to make it simpler, something like finding the max between all dates (the latest date) and compering just this one to the current date
If you want to get best performance, you cannot use greatest(). Instead do something like this:
SELECT *
FROM questions q
JOIN Answers a ON q.user_id = a.user_id
JOIN bestAnswerByPoll p ON a.user_id = p.user_id
JOIN answerThumbRank t ON p.user_id = t.user_id
JOIN notes n ON t.user_id = n.user_id
JOIN interestingQuestion i ON n.user_id = i.user_id
WHERE q.date > curdate() - interval 1 year
AND a.date > curdate() - interval 1 year
AND p.date > curdate() - interval 1 year
AND t.date > curdate() - interval 1 year
AND n.date > curdate() - interval 1 year
AND i.date > curdate() - interval 1 year
You want to avoid datediff() such that MySQL can do index lookup on date column comparisons. Now, to make sure that index lookup works, you should create compound (multi-column) index on (user_id, date) for each one of your tables.
In this compound index, first part (user_id) will be user for faster joins, and second part (date) will be used for faster date comparisons. If you replace * in your SELECT * with only columns mentioned above (like user_id only), you might be able to get index-only scans, which will be super-fast.
UPDATE Unfortunately, MySQL does not support WITH clause for common table expressions like PostgreSQL and some other databases. But, you can still factor out common expression as follows:
SELECT *
FROM questions q
JOIN Answers a ON q.user_id = a.user_id
JOIN bestAnswerByPoll p ON a.user_id = p.user_id
JOIN answerThumbRank t ON p.user_id = t.user_id
JOIN notes n ON t.user_id = n.user_id
JOIN interestingQuestion i ON n.user_id = i.user_id,
(SELECT curdate() - interval 1 year AS year_ago) x
WHERE q.date > x.year_ago
AND a.date > x.year_ago
AND p.date > x.year_ago
AND t.date > x.year_ago
AND n.date > x.year_ago
AND i.date > x.year_ago
In MySQL, you can use the greatest() function:
WHERE DATEDIFF(CURDATE(), greatest(q.date, a.date, p.date, t.date, n.date, i.date)) > 365
This will help with readability. It would not affect performance.