SQL Find Get Item that does not have specific status - mysql

I have the following table:
case_id | run_id | status_id
1 | 44 | 1
1 | 45 | 3
1 | 46 | 1
2 | 44 | 3
2 | 45 | 3
2 | 46 | 3
The table above is the results of the following query:
SELECT t.case_id, t.run_id, t.status_id
FROM `test` t,
(SELECT id FROM `run` WHERE created_on BETWEEN '2019-10-01' AND CURRENT_DATE()) r
WHERE t.run_id = r.id
I'm trying to select only the case_ids that have only 3 in the status_id.
so the query should return case_id 2.

You can use proper, explicit, standard JOIN syntax . . . and then aggregation and filter with a HAVING clause:
select t.case_id
from test t join
run r
on t.run_id = r.id
where r.created_on BETWEEN '2019-10-01' AND CURRENT_DATE()
group by t.case_id
having min(t.status_id) = max(t.status_id) and min(t.status_id) = 3;

You can use aggregation and filter with a having clause:
select t.case_id
from test t
inner join run r on r.id = t.run_id
where r.created_on between '2019-10-01' and current_date()
group by t.case_id
having count(r.status_id <> 3) = 0

Related

Mysql query with group

I have the following table:
id club_id club_option_id created
---|-------|--------------|-------
1 | 1 | 2 | 2015-02-11 16:31:23
2 | 1 | 3 | 2015-02-11 16:31:23
3 | 2 | 2 | 2015-03-06 08:16:02
I would like to select the club (club_id) who has both options (2 and 3)
I don't get any results with the following query:
SELECT club_id FROM
club_options_to_clubs
WHERE club_option_id = 2 AND club_option_id = 3
GROUP BY club_id
How can I get club_id 1 as a result?
You can do as below -
select
t1.club_id from table_name t1
where t1.club_option_id = 2
and exits (
select 1 from table_name t2
where t1.club_id = t2.club_id
and t2.club_option_id = 3
)
The other way is
select club_id from table_name
where club_option_id in (2,3)
group by club_id
having count(*) = 2
With the above approach if you need to check multiple club_option_id pass them in the in function and then use the number in having count(*) = n
Here n = number of items in the in function.

MySQL query for distinct rows on count

I have such query that gives me results about bestseller items from shops, at the moment it works fine, but now I want to get only one product from each shop so to have a distinct si.shop_id only one bestseller product from a shop
SELECT `si`.`id`, si.shop_id,
(SELECT COUNT(*)
FROM `transaction_item` AS `tis`
JOIN `transaction` as `t`
ON `t`.`id` = `tis`.`transaction_id`
WHERE `tis`.`shop_item_id` = `si`.`id`
AND `t`.`added_date` >= '2014-02-26 00:00:00')
AS `count`
FROM `shop_item` AS `si`
INNER JOIN `transaction_item` AS `ti`
ON ti.shop_item_id = si.id
GROUP BY `si`.`id`
ORDER BY `count` DESC LIMIT 7
and that gives mu a result like:
+--------+---------+-------+
| id | shop_id | count |
+--------+---------+-------+
| 425030 | 38027 | 111 |
| 291974 | 5368 | 20 |
| 425033 | 38027 | 18 |
| 291975 | 5368 | 12 |
| 142776 | 5368 | 10 |
| 397016 | 38027 | 9 |
| 291881 | 5368 | 8 |
+--------+---------+-------+
any ideas?
EDIT
so I created a fiddle for it
http://sqlfiddle.com/#!2/cfc4c/1
Now the query returns best selling products I want it to return only one product from shopso the result of fiddle should be
+----+---------+-------+
| ID | SHOP_ID | COUNT |
+----+---------+-------+
| 1 | 222 | 3 |
| 4 | 333 | 2 |
| 8 | 555 | 1 |
| 9 | 777 | 1 |
+----+---------+-------+
Possibly something like this:-
SELECT si.shop_id,
SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(':', si.id, sub1.item_count) ORDER BY sub1.item_count DESC), ',', 1) AS `count`
FROM shop_item AS si
INNER JOIN
(
SELECT tis.shop_item_id, COUNT(*) AS item_count
FROM transaction_item AS tis
JOIN `transaction` as t
ON t.id = tis.transaction_id
AND t.added_date >= '2014-02-26 00:00:00'
GROUP BY tis.shop_item_id
) sub1
ON sub1.shop_item_id = si.id
GROUP BY si.shop_id
ORDER BY `count` DESC LIMIT 7
The sub query gets the count of items for each shop. Then the main query concatenates the item id and the item count together, group concatenates all those for a single shop together (ordered by the count descending) and then uses SUBSTRING_INDEX to grab the first one (ie, everything before the first comma).
You will have to split up the count field to get the item id and count separately (the separator is a : ).
This is taking a few guesses about what you really want, and with no table declares or data it isn't tested.
EDIT - now tested with the SQL fiddle example:-
SELECT SUBSTRING_INDEX(`count`, ':', 1) AS ID,
shop_id,
SUBSTRING_INDEX(`count`, ':', -1) AS `count`
FROM
(
SELECT si.shop_id,
SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(':', si.id, sub1.item_count) ORDER BY sub1.item_count DESC), ',', 1) AS `count`
FROM shop_item AS si
INNER JOIN transaction_item AS ti
ON ti.shop_item_id = si.id
INNER JOIN
(
SELECT tis.shop_item_id, COUNT(*) AS item_count
FROM transaction_item AS tis
JOIN `transaction` as t
ON t.id = tis.transaction_id
AND t.added_date >= '2014-02-26 00:00:00'
GROUP BY tis.shop_item_id
) sub1
ON sub1.shop_item_id = si.id
GROUP BY si.shop_id
) sub2
ORDER BY `count` DESC LIMIT 7;

Mysql - Select at least one or select none

I have a table as so...
----------------------------------------
| id | name | group | number |
----------------------------------------
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 3 | james | 2 | 2 |
| 4 | steven | 2 | 5 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
----------------------------------------
I'm running a select like so:
SELECT * FROM table WHERE number IN (2,3);
The problem im trying to solve is that I want to only grab get results from groups that have 1 or more rows of each number. For instance the above query is returning id's 1-2-3-5-6, when I'd like the results to exclude id 3 since the group of '2' can only return 1 result for the number of '2' and not for BOTH 2 and 3, since there's no row with the number 3 for the group 2 i'd like it to not even select id 3 at all.
Any help would be great.
Try it this way
SELECT *
FROM table1 t
WHERE number IN(2, 3)
AND EXISTS
(
SELECT *
FROM table1
WHERE number IN(2, 3)
AND `group` = t.`group`
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
)
or
SELECT *
FROM table1 t JOIN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
) q
ON t.`group` = q.`group`;
or
SELECT *
FROM table1
WHERE `group` IN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
);
Sample output (for both queries):
| ID | NAME | GROUP | NUMBER |
|----|-------|-------|--------|
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
Here is SQLFiddle demo
On this, you can approach from a fun way with multiple joins for what you WANT qualified, OR, apply a prequery to get all qualified groups as others have suggested, but readability is a bit off for me..
Anyhow, here's an approach going through the table once, but with joins
select DISTINCT
T.id,
T.Name,
T.Group,
T.Number
from
YourTable T
Join YourTable T2
on T.Group = T2.Group AND T2.Group = 2
Join YourTable T3
on T.Group = T3.Group AND T3.Group = 3
where
T.Number IN ( 2, 3 )
So on the first record, it is pointing to by it's own group to the T2 group AND the T2 group is specifically a 2... Then again, but testing the group for the T3 instance and T3's group is a 3.
If it cant complete the join to either of the T2 or T3 instances, the record is done for consideration, and since indexes work great for joins like this, make sure you have one index for your NUMBER criteria, and another index on the (GROUP, NUMBER) for those comparisons and the next query sample...
If doing by more than this simple 2, but larger group, prequery qualified groups, then join to that
select
YT2.*
from
( select YT1.group
from YourTable YT1
where YT1.Number in (2, 3)
group by YT1.group
having count( DISTINCT YT1.group ) = 2 ) PreQualified
JOIN YourTable YT2
on PreQualified.group = YT2.group
AND YT2.Number in (2,3)
Maybe this,if I understand you
SELECT id FROM table WHERE `group` IN
(SELECT `group` FROM table WHERE number IN (2,3)
GROUP BY `group`
HAVING COUNT(DISTINCT number)=2)
SQL Fiddle
This will return all ids where BOTH numbers exist in a group.Remove DISTINCT if you want ids for groups where just one numbers is in.

combining 2 select statements with different number of columns, where 1st statement is already using JOIN

I'm trying to combine 2 select statements with different number of columns.
The 1st statement is this:
SELECT s.id, s.date_sent, m.sam_subject, m.sam_msg_id, (SELECT
COUNT(id) FROM tbl_something WHERE schedule_id = s.id) AS
total_recipients FROM tbl_something2 AS s INNER JOIN
tbl_something3 AS m ON s.message_id = m.sam_msg_id ORDER BY
s.date_sent DESC
The 2nd statement:
SELECT * FROM sms_something4 WHERE status = '0' ORDER BY id DESC
the table output for the 1st statement:
id date_sent sam_subject sam_msg_id total_recipients
1 1372880628 e-Newsletter 2 2
output for 2nd:
id | subject | sent | failed | date_sent | data_sent | data_failed | message | sam_uid from | select_members | status | from_no
11 | test | 2 | 0 | 1372881670 | 639176286411,639224588324 | | | | | | 0 | 0
any suggestions on how would i be able to combine these two statements?
my target output is
id | subject | sent | failed | date_sent | sam_subject | total_recipients | date_sent for email
sam_msg_id can be ignored.
Thank you.
here is basic that you need to have .. you might have to trouble shoot. add column as you need.
SELECT *
FROM (
SELECT s.id, s.date_sent, m.sam_subject, m.sam_msg_id, (SELECT COUNT(id)
FROM tbl_something
WHERE schedule_id = s.id) AS total_recipients
FROM tbl_something2 AS s
INNER JOIN tbl_something3 AS m
ON s.message_id = m.sam_msg_id
) as tbl
INNER JOIN (SELECT * FROM sms_something4 WHERE status = '0') as tbl2
ON tbl2.subject = tbl.sam_subject
and tbl.date_sent=tbl2.date_sent
and tbl.total_Recipients = tbl2.sent+ tbl2.failed
ORDER BY tbl.date_sent DESC
As AJP said you can just do this:
SELECT s.id, a.subject,a.sent, s.date_sent, m.sam_subject,
(SELECT COUNT(id) FROM tbl_something WHERE schedule_id = s.id) AS total_recipients
FROM tbl_something2 AS s
INNER JOIN tbl_something3 AS m ON s.message_id = m.sam_msg_id
INNER JOIN
(
SELECT * FROM sms_something4 WHERE status = '0' ORDER BY id DESC
) a on a.subject = m.sam_subject and a.date_sent = s.date_sent
ORDER BY
s.date_sent DESC

MySQL Join and Subqueries

I currently have the following tables:
Case_Workflows
case_id (PK) | work_id (PK) | date
1 | 1 | 2011-12-12
1 | 4 | 2011-12-13
2 | 6 | 2011-12-18
Workflows
work_id (PK) | status_id
1 | 1
2 | 1
3 | 1
4 | 2
5 | 2
6 | 3
Statuses
status_id (PK) | title
1 | abc
2 | def
3 | ghi
What I am attempting to do is pull a count of the total number of cases with a specific status such as 'abc'. The snag is that each case can have multiple workflows and I only want the single most recent one for each case.
The end result should be:
Status: abc - Count: 2
This is what I have so far:
SELECT COUNT(cases.case_id) as countNum
FROM $this->_caseTable
JOIN case_workflows
ON cases.case_id = cases_workflows.case_id
JOIN workflows
ON cases_workflows.workflow_id = workflows.workflow_id
JOIN statuses
ON workflow.status_id = statuses.status_id
WHERE cases.date > '2011-12-12'
AND cases.date <= '2011-12-18'
What I am unsure on is how to first select the latest work_id for each case, and then grabbing its status_id to match it to a WHERE clause such as WHERE statuses.title = 'abc'
SELECT COUNT(*) as countNum
FROM $this->_caseTable
JOIN workflows
ON workflows.workflow_id =
( SELECT workflow_id
FROM cases_workflows AS mcwf
WHERE mcwf.case_id = cases.case_id
ORDER BY date DESC
LIMIT 1
)
JOIN statuses
ON workflow.status_id = statuses.status_id
WHERE cases.date > '2011-12-12'
AND cases.date <= '2011-12-18'
AND statuses.title = 'abc'
From what I'm understanding here, you need to add statuses.title to your SELECT clause, and then add a GROUP BY clause:
SELECT statuses.title, COUNT(cases.case_id) as countNum
FROM $this->_caseTable
JOIN (SELECT case_id, work_id, max(date)
FROM case_workflows
GROUP BY work_id
WHERE case_id = cases.case_id) cw
ON cases.case_id = cw.case_id
JOIN workflows
ON cw.workflow_id = workflows.workflow_id
JOIN statuses
ON workflow.status_id = statuses.status_id
GROUP BY statuses.title
WHERE cases.date > '2011-12-12'
AND cases.date <= '2011-12-18'