MySQL: One To Many Combinations - mysql

Below is the table data (Order_audit)
+------------+-----------------+
| OrderID | shipping_type |
+------------+-----------------+
| W1 | 0 |
| W1 | 2 |
| W2 | 2 |
| W3 | 2 |
| W3 | 2 |
| W3 | 1 |
| W4 | 0 |
| W5 | 1 |
| W5 | 2 |
+------------+-----------------+
I want sql to extract orderID having shipping_type with combinations of (0 or 1) and 2. In this example W1,W3,W5 are orders which fall in this criteria.
Assuming Table Name is order_audit.
Kindly help me on this.

We can try aggregating by OrderID and then asserting the following two conditions on each order group:
There are two (and only two) distinct shipping_type values present
One of those shipping_type values is 2
If both of the above conditions are true, it would imply that the order had either (0, 2) or (1, 2) as shipping combinations.
SELECT OrderID
FROM yourTable
WHERE shipping_type IN (0, 1, 2)
GROUP BY OrderID
HAVING
COUNT(DISTINCT shipping_type) = 2 AND
MAX(CASE WHEN shipping_type = 2 THEN 1 ELSE 0 END) = 1;
Demo

One way to do it would be with this query which looks for all orders which have a shipping_type of 0 or 1 and have a matching entry with a shipping_type of 2.
SELECT OrderID
FROM order_audit a1
WHERE shipping_type IN(0,1) AND
EXISTS (SELECT *
FROM order_audit a2
WHERE a2.OrderID = a1.OrderID AND shipping_type = 2)
Demo

Related

How to get calculated data from one column in database

im new in sql. I cannot get data with format what i want in one step. Now i'm using more sql commands. I want to get all data in one command because i cant to connect them in subquery with group by. Somebodys can help me?
example of Table i have:
id
order_id
order_status
1
1
0
2
1
0
3
1
0
4
1
1
5
1
1
6
2
0
7
2
0
8
2
1
Table i want to have after sql query:
order_id
count
of
progress(%)
1
2
5
40
2
1
3
33
queries i use:
SELECT order_id, COUNT(status) as count
FROM `orders`
WHERE status = 1
GROUP by order_id;
SELECT order_id, COUNT(status) as of
FROM `orders`
GROUP by order_id;
SELECT order_id,
CAST((SELECT COUNT(status) FROM `orders` WHERE status = 1) /
(SELECT COUNT(status) FROM `orders`) *100 as int) AS progress FROM orders
group by order_id;
but last working properly only if i use where to single order id.
I want to make this data in one sql query to format i showed up.
Thanks a lot guys!
You don't need subqueries to do this, SQL's ordinary aggregate functions already work as you want with your group by clause:
SELECT order_id,
SUM(order_status) AS `count`,
COUNT(*) AS `of`,
SUM(order_status) / COUNT(order_status) * 100 as `progress`
FROM orders
group by order_id;
See example at http://sqlfiddle.com/#!9/d1799db/4/0
you need to use multiple subqueries
here's a query that I used and worked on your example on the onecompiler.com website
-- create
CREATE TABLE EMPLOYEE (
order_id INTEGER,
order_status INTEGER
);
-- insert
INSERT INTO EMPLOYEE VALUES (1,0 );
INSERT INTO EMPLOYEE VALUES (1, 0);
INSERT INTO EMPLOYEE VALUES (1, 0);
INSERT INTO EMPLOYEE VALUES (1, 1);
INSERT INTO EMPLOYEE VALUES (1,1 );
INSERT INTO EMPLOYEE VALUES (2, 0);
INSERT INTO EMPLOYEE VALUES (2, 0);
INSERT INTO EMPLOYEE VALUES (2, 1);
select *
from EMPLOYEE;
SELECT order_id, count, off , count/off
from(
select distinct order_id as order_id,
(select count(order_id) from EMPLOYEE C WHERE A.order_id=C.order_id AND order_status =1) as 'count',
(select count(order_id) from EMPLOYEE B WHERE A.order_id=B.order_id ) as 'off'
FROM EMPLOYEE A
) AA
;
You need to use sum and count with group by.
create table orders(
id int,
order_id int,
order_status int);
insert into orders values
(1,1,0),
(2,1,0),
(3,1,0),
(4,1,1),
(5,1,1),
(6,2,0),
(7,2,0),
(8,2,1);
select
order_id,
sum(order_status) count,
count(order_id) "of",
(100 * sum(order_status))
/ count(order_id) progress
from orders
group by order_id
order by order_id;
order_id | count | of | progress
-------: | ----: | -: | -------:
1 | 2 | 5 | 40.0000
2 | 1 | 3 | 33.3333
db<>fiddle here
i was described my problem without some details, w i want to join with other table but i see only record with status
oders_details
| id | order_describe | order_date |
|:----:|:--------------:|:----------:|
| 1 | sample 1 | 2022-02-28 |
| 2 | sample 2 | 2022-02-28 |
| 3 | sample 3 | 2022-03-01 |
| 4 | sample 4 | 2022-03-02 |
orders_status
| id | order_id |order_status|
|:---:|:---------------:|:----------:|
| 1 | 1 | 0 |
| 2 | 1 | 0 |
| 3 | 1 | 0 |
| 4 | 1 | 1 |
| 5 | 1 | 1 |
| 6 | 2 | 0 |
| 7 | 2 | 0 |
| 8 | 2 | 1 |
table i want after query
orders_view
| id |order_id|order_describe| order_date | count | of | progress |
|-----|--------|--------------|------------|-------|----|:--------:|
| 1 | 1 | sample 1 | 2022-02-28| 2 | 5 | 40 |
| 2 | 2 | sample 2 | 2022-02-28| 1 | 3 | 33 |
| 3 | 3 | sample 3 | 2022-03-01| null |null| null |
| 4 | 4 | sample 4 | 2022-03-02| null |null| null |
i want to get some hint what i have todo, to get finally table or view, not complete solution, to better understand sql lang

MySQL query to select items in a linked table based on AND

I have a table tblPhotos of photo details:
| photoID | photoName |
| ------- | --------- |
| 1 | w |
| 2 | x |
| 3 | y |
| 4 | z |
and another table tblPhotoTags of tags to photos:
| photoID | tagID |
| ------- | ----- |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 2 |
| 4 | 1 |
| 4 | 2 |
I am trying make a couple of queries that will pick out the photos that have any given tags, either AND or OR. In the example let's say I am searching for the photos linked to tagID 1 AND/OR 2.
OR should pick out all of the photos (1, 2, 3 and 4).
AND should only pick out 1 and 4.
I have the following for OR which works fine:
SELECT DISTINCT tblPhotos.photoID FROM tblPhotos
INNER JOIN tblPhotoTags ON tblPhotos.photoID = tblPhotoTags.photoID
WHERE tblPhotoTags.tagID = 1 OR tblPhotoTags.tagID = 2
But I am struggling to work out how to do the AND query.
If you need only the ids of the photos, then there is no need to join to tblPhotos.
For the 1st case (OR), use DISTINCT and just a WHERE clause:
SELECT DISTINCT photoID
FROM tblPhotoTags
WHERE tagID IN (1, 2);
For the 2nd case (AND) use aggregation and set the condition in the HAVING clause:
SELECT photoID
FROM tblPhotoTags
WHERE tagID IN (1, 2)
GROUP BY photoID
HAVING COUNT(*) = 2 -- the number of tagIDs in the IN list
If you also want the name of the photos then join to tblPhotos:
SELECT DISTINCT p.*
FROM tblPhotos p INNER JOIN tblPhotoTags t
ON t.photoID = p.photoID
WHERE t.tagID IN (1, 2);
and:
SELECT p.photoID, p.photoName
FROM tblPhotos p INNER JOIN tblPhotoTags t
ON t.photoID = p.photoID
WHERE t.tagID IN (1, 2)
GROUP BY p.photoID, p.photoName
HAVING COUNT(*) = 2 -- the number of tagIDs in the IN list
See the demo.

SQL Difference between two row in group by

I have a table records of store id, processing batch id and start time as follows:
|store_id | batch_id | process_start_time |
| A | 1 | 10 |
| B | 1 | 40 |
| C | 1 | 30 |
| A | 2 | 400 |
| B | 2 | 800 |
| C | 2 | 600 |
| A | 3 | 10 |
| B | 3 | 80 |
| C | 3 | 90 |
Here, rows needed to be grouped by batch_id and time_taken is difference of process_start_time of store A and store C.
So, the expected result would be:
batch_id | time_taken
1 | 20
2 | 200
3 | 80
I tried to do something like:
select batch_id, ((select process_start_time from records where store_id = 'C') - (select process_start_time from records where store_id = 'A')) as time_taken
from records group by batch_id;
But couldn't figure out to select specific rows in that particular group.
Thank you for looking into!
Update: the process_start_time column not necessarily max for store C
You seem to want conditional aggregation and arithmetic:
select batch_id,
(max(case when store_id = 'C' then process_start_time end) -
min(case when store_id = 'A' then process_start_time end)
) as diff
from records
group by batch_id;
You can try a self join.
SELECT r1.batch_id,
r1.process_start_time - r2.process_start_time time_taken
FROM records r1
INNER JOIN records r2
ON r1.batch_id = r2.batch_id
WHERE r1.store_id = 'C'
AND r2.store_id = 'A';
Here's another answer. This is using two instances of the records table and we link them up with where clauses and exists as follows:
select a.batch_id,
c.process_start_time - a.process_start_time as time_taken
from records a,
records c
where a.store_id = 'A'
and c.store_id = 'C'
and exists (
select 1
from records x
where x.batch_id = a.batch_id
and x.batch_id = c.batch_id
);
SELECT DISTINCT
store_a.batch_id,
store_c.process_start_time - store_a.process_start_time AS 'time_taken'
FROM records store_a
INNER JOIN records store_c
ON store_a.batch_id = store_c.batch_id
AND store_c.store_id = 'C'
AND store_a.store_id = 'A'

Mysql query with multiple conditions on FK

I have slight problem with mysql query. I have two tables:
bioshops
+------------+-------------+
| bioshop_id | name |
+------------+-------------+
| 1 | Bioshop1 |
| 2 | Bioshop2 |
+------------+-------------+
bioshop_have_product
+----+-----------------+--------------+
| id | bioshop_id | product_id |
+----+-----------------+--------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 3 |
+----+-----------------+--------------+
The tables are much more complex but this is the important structure. prodict_id in bioshop_have_product is also FK. I need to select bioshops witch contains all products that I ask. Example:
if I need bioshops with product 1 it should return Bioshop1 and Bioshop2 with all products
if I need bioshops with product 1 and 2 it should return Bioshop1 with all products
My query is:
SELECT bs.name AS name,
bs.id AS bioshop_id,
bshd.id AS id,
bshd.product_id AS product_id
FROM bioshops bs
JOIN bioshop_have_product bshp
ON bs.bioshop_id = bshp.bioshop_id
WHERE (bshp.bioshop_id = bs.bioshop_id AND bshp.product_id = '1')
AND (bshp.bioshop_id = bs.bioshop_id AND bshp.product_id = '2')
but this returns nothing and I want it to return Bioshop1 because only Bioshop1 countains both objects.
You can try something like this:
SELECT bs.name AS name,
bs.id AS bioshop_id,
bshp.id AS id,
bshp.product_id AS product_id
FROM bioshop bs
JOIN bioshop_have_product bshp
ON bs.id = bshp.bioshop_id AND
(SELECT COUNT(*) FROM bioshop_have_product WHERE product_id IN (1, 2) AND bs.id = bioshop_id) = X
where X should be equal to the count of different products you whant to check, for instance 2 in your second case.
SELECT bioshop_id
FROM bioshop_have_product
WHERE product_id IN (1,2)
GROUP
BY bioshop_id
HAVING COUNT(*) = 2;

how to write this self join based on three columns

Hello there I have a following table
------------------------------------------
| id | language | parentid | no_daughter |
------------------------------------------
| 1 | 1 | 0 | 2 |
------------------------------------------
| 1 | 1 | 0 | 2 |
------------------------------------------
| 2 | 1 | 1 | 1 |
------------------------------------------
| 2 | 2 | 1 | 1 |
------------------------------------------
| 3 | 1 | 1 | 0 |
------------------------------------------
| 3 | 2 | 1 | 0 |
------------------------------------------
| 4 | 1 | 2 | 0 |
------------------------------------------
| 4 | 2 | 2 | 0 |
------------------------------------------
| 5 | 1 | 2 | 0 |
------------------------------------------
| 5 | 2 | 2 | 1 |
-----------------------------------------
| 5 | 1 | 4 | 1 |
------------------------------------------
| 5 | 2 | 4 | 1 |
------------------------------------------
Scenario
Every record has more than one rows in table with different language ids. parentid tells who is the parent of this record. no_daughter columns tells against each record that how many child one record has. Means in Ideal scenario If no_daughter has value 2 of id = 1 , it means 1 should be parentid of 2 records in same table. But If a record has more than one exitance with respect to language, it will be considered as one record.
My Problem
I need to find out those records where no_daughter value is not correct. It means if no_daughter is 2, there must be two records whoes parentid has that id. In above case record with id = 1 is valid. But record having id = 2 is not valid because the no_daughter = 1 but actual daughter of this record is 2. Same is the case with id=4
Can any body tell me how can I find these faulty records?
Updated after answers
Ken Clark has and shola has given answer which return same result for example shola query is
SELECT DISTINCT
id
FROM
tbl_info t
INNER JOIN
(SELECT
parentid,
COUNT(DISTINCT id) AS childs
FROM
tbl_info
GROUP BY parentid) AS parentchildrelation
ON t.id = parentchildrelation.parentid
AND t.no_daughters != parentchildrelation.childs
This query is returning those ids who have been used as parentid somewhere in table but having wrong no_daughter values. But not returning ids that has value in no_daugter columns but have not been used as parentid any where in table. For exampl id = 5 has no_daughter = 1 but it is not used as parentid in table. So it is also a faulty record. But above query is not capturing such records.
Any help will be much appreciated.
Try this:
SELECT DISTINCT
id
FROM
tbl_info t
Left JOIN
(SELECT
parentid,
COUNT(DISTINCT id) AS childs
FROM
tbl_info
GROUP BY parentid) AS parentchildrelation
ON t.id = parentchildrelation.parentid
Where t.no_daughters != parentchildrelation.childs
Try this:
SELECT id FROM tinfo t inner join
(SELECT parentid, COUNT(distinct language ) as childs FROM tinfo group by parentid) as summary
on t.id=summary.parentid and t.no_daughters!= summary.childs
try this
Select Distinct * From tablename t
Left Join
(
Select COUNT(t1.Id) Doughter,t1.parentid,t1.language From tablename t1 Group By t1.parentid,t1.language
)tbl
On t.id=tbl.parentid And tbl.language=t.language And t.no_daughter<>tbl.Doughter