how to select from table with those condition? - mysql

the table has 4 columns follows :
id int(11) not null primary key,
name varchar not null ,
status tinyint(1) not null,
created datetime not null
now, I want to find out the result rows with conditions :
the status is 0;
foreach the result rows as A, if the table can select a row name B that has the same name and created is the same day and status is 1, except the A.
could someone select the result with a sql without nested select, thanks a lot!

Sounds like an anti-join pattern fits the bill. This pattern requires two references to the table, but only a single SELECT keyword. As an example:
SELECT t.id
, t.name
, t.status
, t.created
FROM the_table t
-- anti-join exclude matching rows
LEFT
JOIN the_table d
ON d.name = t.name
AND d.status = 1
AND d.created >= DATE(t.created)
AND d.created < DATE(t.created) + INTERVAL 1 DAY
WHERE d.name IS NOT NULL
AND t.status = 0
The trick is the outer join, to return all rows from t, along with matching rows from d, with the condition in the WHERE clause that excludes all rows that had a match. Leaving only rows from t that didn't have a matching row from d.

name not in rows that has second condition:
SELECT * FROM tablename as o
WHERE o.status = 0
AND o.name NOT IN
(
SELECT `name` FROM tablename as i
WHERE i.status = 1
AND i.created
BETWEEN DATE(t.created)
AND DATE(t.created) + INTERVAL 1 DAY
)

Try this:
select a.id,a.name,a.created,a.status from
(select b.id,a.name,b.created,b.status from
(select count(name) as cnt, name from tbl_sample as a GROUP BY name) as a
LEFT JOIN
(select * from tbl_sample) as b
on a.`name` = b.`name` where cnt>1 and STATUS = 0) as a
LEFT JOIN
(select b.id,b.name,b.created,b.status from
(select count(created) as cnt, created from tbl_sample as a GROUP BY created) as a
LEFT JOIN
(select * from tbl_sample) as b
on a.`created` = b.`created` where cnt>1 and STATUS = 0) as b
on a.id = b.id

SELECT a.id, a.name, a.status, a.created
FROM userTable as a
LEFT JOIN userTable as b
ON a.name = b.name
AND b.status = 1
AND b.created BETWEEN DATE(a.created) AND DATE(DATE_ADD(a.created, INTERVAL 1 day))
WHERE a.status = 0
AND a.name IS NULL;
thanks the answer from #spencer7597 , I find out the result.

Related

I need to get specific ids from db if these are in current and last quarter using SQL

[DB Table]
SELECT b.first_name, b.last_name, a.pod_name, a.category, c.user_id,
SUM(IF(QUARTER(CURDATE())-1 OR (QUARTER(CURDATE())-2) AND a.user_id, 1, 0)) AS flag FROM kudos a
INNER JOIN users b ON a.user_id = b.id INNER JOIN users_groups c ON a.user_id = c.user_id
INNER JOIN groups d ON c.group_id = d.id WHERE a.group_name = 'G2' AND d.id IN (7,8,9,11,12,13,14,15,16,17,21,22,23,24,25,26,27,28)
AND QUARTER(CURDATE())-1 = a.quarter ORDER BY a.final_score+0 DESC
I need to get the user_ids of those users which are both in quarter 1 and 2 from table.
Tried above query but failed to get expected results.
Can someone please guide me on this?
if you only need user_id then you can do this :
select user_id
from tablename
where quarter in (1,2)
group by user_id
having count(distinct quarter) = 2
another way is to use window function, assuming you have one user id in each quarter:
select * from (
select * , count(*) over (partition by user_id) cn
from tablename
where quarter in (1,2)
) t where cn = 2

Select customers with no invoices after date

I have Client and Invoice tables. They have one-to-many relationship, where Client.id = Invoice.client_id.
Client columns:
id
Invoice columns:
id,
client_id,
invoice_date
Of course the example is simplified to relevant data.
I am trying to select customers who did NOT have invoices after '2010-01-01'.
I can't figure out any working way to do this. Some routes I took look like this (there many other variations, but no point displaying the here):
SELECT c.id, COUNT(i.invoice_date > "2010-01-01") AS cnt
FROM Client AS c LEFT JOIN Invoice i ON i.client_id = c.id
GROUP BY c.id HAVING cnt = 0
and
SELECT client_id, COUNT(invoice_date > '2010-01-01') as cnt
FROM Invoice
GROUP BY client_id HAVING cnt = 0
You can use a sub-query with NOT EXISTS like this:
SELECT *
FROM Client
WHERE NOT EXISTS (
SELECT 1
FROM Invoice
WHERE Invoice.invoice_date > '2010-01-01' AND Invoice.client_id = Client.id
)
You can also use SUM with CASE or IF:
-- CASE
SELECT c.id, SUM(CASE WHEN i.invoice_date > '2010-01-01' THEN 1 ELSE 0 END) AS cnt
FROM Client AS c LEFT JOIN Invoice i ON i.client_id = c.id
GROUP BY c.id
HAVING cnt = 0
-- IF
SELECT c.id, SUM(IF(i.invoice_date > '2010-01-01', 1, 0)) AS cnt
FROM Client AS c LEFT JOIN Invoice i ON i.client_id = c.id
GROUP BY c.id
HAVING cnt = 0
You can also use COUNT, but with CASE or IF:
-- CASE
SELECT client_id, COUNT(CASE WHEN invoice_date > '2010-01-01' THEN 1 ELSE NULL END) as cnt
FROM Invoice
GROUP BY client_id HAVING cnt = 0
-- IF
SELECT client_id, COUNT(IF(invoice_date > '2010-01-01', 1, NULL)) as cnt
FROM Invoice
GROUP BY client_id HAVING cnt = 0
demo on dbfiddle.uk
You can also use NOT IN with a sub-query
SELECT * FROM client
WHERE id NOT IN (
SELECT client_id
FROM invoice
WHERE invoice_date>'2020-01-01'
);
Try this :-
Select Client.* from Client Client left join Invoice Invoice on
client.id = Invoice.client_id and Invoice.invoice_date > "2010-01-01"
where Invoice.client_id is null;
Basically you include only the subset of the data after "2010-01-01" from the invoice table.

MySQL SELECT subquery

I have a calendar and user_result table and I need to join these two queries.
calendar query
SELECT `week`, `date`, `time`, COUNT(*) as count
FROM `calendar`
WHERE `week` = 1
GROUP BY `date`
ORDER BY `date` DESC
and the result is
{"week":"1","date":"2014-08-21","time":"15:30:00","count":"4"}, {"week":"1","date":"2014-08-20","time":"17:30:00","count":"12"}
user_result query
SELECT `date`, SUM(`point`) as score
FROM `user_result`
WHERE `user_id` = 1
AND `date` = '2014-08-20'
and the result is just score 3
My goal is to always show calendar even if the user isn't present in the user_result table, but if he is, SUM his points for that day where calendar.date = user_result.date. Result should be:
{"week":"1","date":"2014-08-21","time":"15:30:00","count":"4","score":"3"}, {"week":"1","date":"2014-08-20","time":"17:30:00","count":"12","score":"0"}
I have tried this query below, but the result is just one row and unexpected count
SELECT c.`week`, c.`date`, c.`time`, COUNT(*) as count, SUM(p.`point`) as score
FROM `calendar` c
INNER JOIN `user_result` p ON c.`date` = p.`date`
WHERE c.`week` = 1
AND p.`user_id` = 1
GROUP BY c.`date`
ORDER BY c.`date` DESC
{"week":"1","date":"2014-08-20","time":"17:30:00","count":"4","score":"9"}
SQL Fiddle
ow sorry, i was edited, and i was try at your sqlfiddle, if you want to show all date from calendar you can use LEFT JOIN, but if you want to show just the same date between calendar and result you can use INNER JOIN, note: in this case INNER JOIN just show 1 result, and LEFT JOIN show 2 results
SELECT c.`week`, p.user_id, c.`date`, c.`time`, COUNT(*) as count, p.score
FROM `calendar` c
LEFT JOIN
(
SELECT `date`, SUM(`point`) score, user_id
FROM `result`
group by `date`
) p ON c.`date` = p.`date`
WHERE c.`week` = 1
GROUP BY c.`date`
ORDER BY c.`date` DESC
I put a pre-aggreate query / group by date as a select for the one person you were interested in... then did a left-join to it. Also, your column names of week, date and time (IMO) are poor choice column names as they can appear to be too close to reserved keywords in MySQL. They are not, but could be confusing..
SELECT
c.week,
c.date,
c.time,
coalesce( OnePerson.PointEntries, 0 ) as count,
coalesce( OnePerson.totPoints, 0 ) as score
FROM
calendar c
LEFT JOIN ( select
r.week,
r.date,
COUNT(*) as PointEntries,
SUM( r.point ) as totPoints
from
result r
where
r.week = 1
AND r.user_id = 1
group by
r.week,
r.date ) OnePerson
ON c.week = OnePerson.week
AND c.date = OnePerson.date
WHERE
c.week = 1
GROUP BY
c.date
ORDER BY
c.date DESC
Posted code to SQLFiddle

MySQL: SELECT if non of group by members is equal to x

I have troubles getting proper data.
I have table structure like:
id INT(11) AI
order_id INT(11)
status varchar(45)
This table log status changes for orders.
So order_id's will have few statuses.
Now I need to select rows and group them by order_id, where order never had status (not even one status with given order_id) != 'example'
We don't show orders, where one of members had status = example
Sample data
1 12 ready
1 12 example
2 13 ready
2 13 sent
So I don't want order 12 to show at all, because one of it members have "example" status
I've tried grouping results, but it's not enough.
you can do it by simple join query :
select a.order_id
from ordrstatus as a left outer join (select orderid , count(*) as status from orderstatus where status = 'example' group by orderid) as b on a.orderid = b.orderid
where b.status = 0 or b.status is NUll
Join query always run faster then IN query . by using Join in query it will run only one time .
You can try like this...it will return all order id which never had status -example
Select
Order_id,
from TableName A where Not Exists(
Select id from TableName B where
status='example' and
a.Order_id=b.Order_id
)
group by Order_id
Not quite sure if you want the records for order which have had a status of example, or ones which have never had a status of example
To get a list of orders (with the status grouped up) which have had a status of example:-
SELECT a.order_id, GROUP_CONCAT(a.status)
FROM SomeTable a
INNER JOIN
(
SELECT order_id, COUNT(*)
FROM SomeTable
WHERE status = 'example'
GROUP BY order_id
) b
ON a.order_id = b.order_id
GROUP BY order_id
To get those which have NEVER had a status of exmaple
SELECT a.order_id, GROUP_CONCAT(a.status)
FROM SomeTable a
LEFT OUTER JOIN
(
SELECT order_id, COUNT(*)
FROM SomeTable
WHERE status = 'example'
GROUP BY order_id
) b
ON a.order_id = b.order_id
WHERE b.order_id IS NULL
GROUP BY order_id
EDIT
SELECT a.order_id, GROUP_CONCAT(a.status)
FROM SomeTable a -- Statuses
LEFT OUTER JOIN
(
SELECT order_id, COUNT(*)
FROM SomeTable
WHERE status = 'example'
GROUP BY order_id
) b -- Get any order id which has had a status of example (as a LEFT JOIN)
ON a.order_id = b.order_id
INNER JOIN
(
SELECT order_id, MAX(id) AS Latestid
FROM SomeTable
GROUP BY order_id
) c -- Get the latest status for each order (ie, max id)
ON a.order_id = c.order_id
LEFT OUTER JOIN
(
SELECT order_id, id
FROM SomeTable
WHERE status = 'example2'
) d -- Get the id of the order status of example2
ON a.order_id = d.order_id AND c.Latestid = d.id -- join on the same order id and that the record id matches the latest record id
WHERE b.order_id IS NULL -- reject those where a match was found on example for any status
AND d.order_id IS NULL -- reject those where a match was found on example2 for the latest status
GROUP BY order_id
try this
SELECT Order_ID FROM tbl_Orders
WHERE Status NOT IN ('example')
GROUP BY Order_ID
SELECT DISTINCT x.order_id
FROM order_status x
LEFT
JOIN order_status y
ON y.order_id = x.order_id
AND y.status = 'example'
WHERE y.id IS NULL;

MySQL - JOIN only if a row exists from the left table

Here is MySQL:
SELECT a.id,
a.name,
a.n,
a.r,
a.pot,
a.ticket_price,
a.starting_tickets,
a.started,
a.end,
COUNT(b.id) tickets_bought
FROM current_lotteries a
JOIN lottery_tickets b ON b.lid=a.id
WHERE a.cid=1
ORDER BY started DESC LIMIT 1
In the search, if there is no row from a but there are rows in b (i.e COUNT(b.id) is not NULL) then this query returns a row with NULL values for a fields and whatever the value of COUNT(b.id) as tickets_bought. How do I modify this query so it does not return a row (num_rows = 0) if there is no result in table a?
A Snap.
Absent a GROUP BY clause, MySQL (which permits this where it would be an error in other RDBMS) is applying the aggregate group over all rows in b when it should be grouping them. Add GROUP BY a.id
SELECT a.id,
a.name,
a.n,
a.r,
a.pot,
a.ticket_price,
a.starting_tickets,
a.started,
a.end,
COUNT(b.id) tickets_bought
FROM current_lotteries a
JOIN lottery_tickets b ON b.lid=a.id
WHERE a.cid=1
GROUP BY a.id
ORDER BY started DESC LIMIT 1
The above will work in MySQL but not elsewhere. A more portable version uses a correlated subquery:
SELECT a.id,
a.name,
a.n,
a.r,
a.pot,
a.ticket_price,
a.starting_tickets,
a.started,
a.end,
b.tickets_bought
FROM current_lotteries a
/* More portable to join against a subquery which returns the count per group */
JOIN (
SELECT b.lid, COUNT(*) AS tickets_bought
FROM lottery_tickets
GROUP BY lid
) b ON a.id = b.lid
WHERE a.cid = 1
ORDER BY started DESC LIMIT 1
Try this:
SELECT a.id, a.name, a.n, a.r, a.pot, a.ticket_price,
a.starting_tickets, a.started, a.end, b.tickets_bought
FROM current_lotteries a
RIGHT JOIN (SELECT b.lid, COUNT(*) AS tickets_bought
FROM lottery_tickets GROUP BY lid ) b ON a.id = b.lid
WHERE a.cid = 1
ORDER BY started DESC
LIMIT 1;