Mysql select with multiple condition - mysql

I would need help creating a query
Table A
+------------+--------------------+-------+
| product_id | name | price |
+------------+--------------------+-------+
| 13 | Product 13 | 5 |
| 14 | Product 14 | 2 |
| 15 | Product 15 | 3 |
| 16 | Product 16 | 2 |
| 17 | Product 17 | 15 |
+------------+--------------------+-------+
Table B
+----+------------+-------------+
| id | product_id | taxonomy_id |
+----+------------+-------------+
| 10 | 13 | 5 |
| 11 | 13 | 2 |
| 12 | 14 | 3 |
| 13 | 15 | 2 |
| 14 | 16 | 15 |
| 14 | 16 | 5 |
| 14 | 16 | 19 |
| 14 | 16 | 21 |
| 14 | 16 | 18 |
+----+------------+-------------+
my attempt
SELECT *
FROM A
LEFT JOIN B ON B.product_id = A.product_id
WHERE IF(B.taxonomy_id IN ('5','15'),
IF(B.taxonomy_id IN ('2'), 1, 0), 0) = 1
GROUP BY A.product_id
I need it to give me back those results from table A for which it is true
B.taxonomy_id is "5" OR "15" and B.taxonomy_id is "2"
The result would be for this example -> product_id - 13
and I also need to get a number of results SELECT count(*) ... -> return is 1

Is it normal that your tables don't have an id column as a unique primary key ?
Anyway, here is what I came across, tell me if it works :
SELECT table_nameA.product_id
FROM table_nameA
LEFT JOIN table_nameB on table_nameA.product_id = table_nameB.product_id
WHERE taxonomy_id = 2 AND table_nameA.product_id IN
(SELECT table_nameA.product_id
FROM table_nameA
LEFT JOIN table_nameB on table_nameA.product_id = table_nameB.product_id
where taxonomy_id = 5 or taxonomy_id = 15
GROUP BY table_nameA.product_id, taxonomy_id)
Result is :
| product_id |
|------------|
| 13 |
About your count query, it is exactly the same.
SELECT count(table_nameA.product_id) as Quantity
FROM table_nameA
LEFT JOIN table_nameB on table_nameA.product_id = table_nameB.product_id
WHERE taxonomy_id = 2 AND table_nameA.product_id IN
(SELECT table_nameA.product_id
FROM table_nameA
LEFT JOIN table_nameB on table_nameA.product_id = table_nameB.product_id
where taxonomy_id = 5 or taxonomy_id = 15
GROUP BY table_nameA.product_id, taxonomy_id)
Result is :
| Quantity |
|----------|
| 1 |

Instead of doing filtering in the WHERE clause; you need to do this conditional filtering inside the HAVING clause. You can avoid LEFT JOIN, as the product should have taxonomies for them (2 AND (5 or 15)):
SELECT a.product_id
FROM tablea a
JOIN tableb b on b.product_id = a.product_id
GROUP BY a.product_id
HAVING SUM(b.taxonomy_id IN (5,15))
AND SUM(b.taxonomy_id = 2)
Result
| product_id |
| ---------- |
| 13 |
View on DB Fiddle

You can use exists:
select a.*
from a
where exists (select 1
from b
where b.product_id = a.product_id and
b.taxonomy_id in (5, 15)
) and
exists (select 1
from b
where b.product_id = a.product_id and
b.taxonomy_id in (2)
) ;
If you just wanted the product_ids, then I would recommend aggregation:
select b.product_id
from b
where b.taxonomy_id in (2, 5, 15)
group by b.product_id
having sum( b.taxonomy_id in (5, 15) ) > 0 and
sum( b.taxonomy_id in (2) ) > 0 ;

You can use either join with having clause or intersect function with 2 queries to get the output
13
in your senario.
Join with having clause:
select a.product_id from a inner join b on a.product_id = b.product_id group by a.product_id having (SUM (b.taxonomy_id IN (5,15)) and SUM (b.taxonomy_id in (2)));
Intersect with 2 queries:
select a.product_id from a where (a.product_id IN (select product_id from b where b.taxonomy_id = 2))
INTERSECT
select a.product_id from a where (a.product_id IN (select product_id from b where b.taxonomy_id in (5,15)));
For count use something like this which will return
1
as an output:
select COUNT(*) from (select a.product_id from a where (a.product_id IN (select product_id from b where b.taxonomy_id = 2))
INTERSECT
select a.product_id from a where (a.product_id IN (select product_id from b where b.taxonomy_id in (5,15)))) I;

Related

How to resolve the below nested JOIN function error

Base Data:
-----------------------
Date | ID | PL |
-----------------------
16.09.2019| 21 | 0 |
17.09.2019| 21 | 0 |
18.09.2019| 21 | 1 |
19.09.2019| 21 | 2 |
Expected Output:
-----------------------------------
Date | ID | PL | ZC | TC |
-----------------------------------
16.09.2019| 21 | 0 | 2 | 4 |
17.09.2019| 21 | 0 | 2 | 4 |
18.09.2019| 21 | 1 | 2 | 4 |
19.09.2019| 21 | 2 | 2 | 4 |
Code is working with single JOIN function but not with the below code
SELECT [4G].*,Z.ZC,T.TC
FROM 4G
LEFT JOIN (SELECT COUNT([4G].[ID]) AS ZC, [4G].[ID]
FROM 4G
WHERE [4G].[PL] =0
GROUP BY [4G].[ID])
AS Z
ON [4G].[ID] = Z.[ID]
LEFT JOIN (SELECT COUNT([4G].[ID]) AS TC, [4G].[ID]
FROM 4G
GROUP BY [4G].[ID])
AS T
ON [4G].[ID] = T.[ID];
ERROR Shown is:
"Syntax Error(missing operator) in query expression
'[4G].[ID] = Z.[ID]
LEFT JOIN (SELECT COUNT([4G].[ID]) AS TC, [4G].[ID]
FROM 4G
GROUP BY [4G].[ID])
AS T
ON [4G].[ID] = T.[ID]'
Access requires parentheses for each pair of joined tables before another join:
SELECT [4G].*,Z.ZC,T.TC
FROM ([4G]
LEFT JOIN (
SELECT COUNT([4G].[ID]) AS ZC, [4G].[ID]
FROM [4G]
WHERE [4G].[PL] =0
GROUP BY [4G].[ID]
) AS Z ON [4G].[ID] = Z.[ID])
LEFT JOIN (
SELECT COUNT([4G].[ID]) AS TC, [4G].[ID]
FROM [4G]
GROUP BY [4G].[ID]
) AS T ON [4G].[ID] = T.[ID];
Results:
Date ID PL ZC TC
16/9/2019 21 0 2 4
17/9/2019 21 0 2 4
18/9/2019 21 1 2 4
19/9/2019 21 2 2 4

MySQL select rows where its columns sum equal value

I have following tables:
A:
+----+-----------+-------+----------+
| ID | PaymentID | Price | Quantity |
+----+-----------+-------+----------+
| 1 | 1 | 128 | 1 |
| 2 | 2 | 10 | 2 |
| 3 | 2 | 11 | 1 |
| 4 | 3 | 100 | 2 |
+----+-----------+-------+----------+
B:
+-----------+------------+
| PaymentID | TotalPrice |
+-----------+------------+
| 1 | 128 |
| 2 | 31 |
| 3 | 201 |
+-----------+------------+
And query:
SELECT a.ID
FROM a
LEFT JOIN b ON b.PaymentID = a.PaymentID
WHERE b.TotalPrice = (a.Price * a.Quantity)
It works fine when a.PaymentID is unique, but some transactions in table A are separated and paid (table B) together. Query above return a.ID = 1 but I need to return a.ID = 1,2,3.
a.PaymentID(1): 128 * 1 = 128 MATCH
a.PaymentID(2): 10 * 2 + 11 * 1 = 31 MATCH
a.PaymentID(3): 100 * 2 = 200 NOT MATCH
SQL Fiddle
You are trying to join sum of Price and amount from table a to table b along with the PaymentId, and using it onto a joining clause which would be calculated per row based not on aggregate based.
You may need to first find the aggregate part and then join something as
select
a.ID
from a
left join (
select sum(Price*Quantity) as tot,PaymentID
from a group by PaymentID
)x on x.PaymentID = a.PaymentID
join b on b.PaymentID = a.PaymentID and x.tot = b.TotalPrice
http://www.sqlfiddle.com/#!9/3b261/45
Try this statement:
SELECT a.ID, b.totalprice
FROM a
LEFT JOIN b ON b.PaymentID = a.PaymentID
group by b.paymentID
having TotalPrice = sum(a.Price * a.Quantity)
SQLFIDDLE
UPDATE: After clarification:
select a.id from a where paymentId in(
select paymentID from(
SELECT a.paymentID as paymentID, b.totalprice
FROM a
LEFT JOIN b ON b.PaymentID = a.PaymentID
group by b.paymentID
having TotalPrice = sum(a.Price * a.Quantity)) as c )

Count total number of occurrence of two consecutive values in a table

My table structure
+----+--------+
| id | status |
+----+--------+
| 1 | 10 |
| 2 | 21 |
| 3 | 22 |
| 4 | 29 |
| 5 | 30 |
| 6 | 32 |
| 7 | 33 |
| 8 | 21 |
| 9 | 22 |
| 10 | 23 |
| 11 | 21 |
| 12 | 22 |
| 13 | 23 |
+----+--------+
I want to count total number of times when status 22 comes just after status 21.
In this case the query should return 3.
sql fiddle
Just use a Self Join with Conditional Aggregate
SELECT Sum(CASE WHEN a.status = 22 AND b.status = 21 THEN 1 END) As Stat_Count
FROM testTable a
LEFT OUTER JOIN testTable b
ON a.id = b.id + 1
SQLFIDDLE DEMO
If you can have gaps in your id's you can use a subquery to check whether the previous status of a 22 row is 21
select count(*)
from testtable a
where a.status = 22 and (select status from testtable b
where b.id < a.id order by id desc limit 1) = 21
http://sqlfiddle.com/#!2/9d567/2
Another way gets all id's of previous rows of rows with a status of 22 in derived table and then joins the ids to count how many have a status of 21
select count(*) from (
select max(b.id) max_b_id
from testtable a join testtable b on b.id < a.id
where a.status = 22
group by a.id
) t1 join testtable a on a.id = t1.max_b_id
where a.status = 21
I have tried to solve it in php
$q="";
$q= mysqli_query("select *from testTable");
while($r=mysqli_fetch_assoc($q)){
$rows[]=$r;
}
$success=0;
for ($i=0;$i<count($rows);$i++){
if($rows[$i]['status']==21 and $rows[$i+1]['status']==22 ){
$success+=1;
}
}
echo $success;

SQL select orders depending on status and date

I have a table order_history that is similar to the following:
+-------------------------------------------------------------+
| order_history_id | order_id | order_status_id | date_addded |
+-------------------------------------------------------------+
| 1 | 1 | 1 | 2014-03-20 |
| 2 | 1 | 2 | 2014-03-21 |
| 3 | 1 | 3 | 2014-03-29 |
| 4 | 2 | 1 | 2014-03-20 |
| 5 | 2 | 2 | 2014-03-21 |
| 6 | 2 | 3 | 2014-04-02 |
| 7 | 3 | 1 | 2014-04-20 |
| 8 | 3 | 2 | 2014-04-21 |
| 9 | 3 | 3 | 2014-04-22 |
+-------------------------------------------------------------+
The order_status represents the status of an order
+-------------------------------+
| order_status_id | name |
+-------------------------------+
| 1 | received |
| 2 | processed |
| 3 | shipped |
+-------------------------------+
what i want to do is to pull out all the orders that have been received before 2014-04-01 but not shipped until after 2014-04-01.
So in this case the query would just return order_id 2 as this is the only order that was received before 2014-04-01 yet shipped after.
I can't even seem to get started... Any help, hints, or pointers much appreciated.
You can do so ,by joining your tables and count the statues shipped for each order by using expression in sum i.e SUM(os.name ='shipped') shipped
SELECT o.*
,SUM(os.name ='shipped') shipped
FROM
orders o
LEFT JOIN orders_status os USING(order_status_id)
WHERE o.date_addded < '2014-04-01'
GROUP BY o.order_id
HAVING shipped =0
Fiddle Demo
You can use INNER JOIN with this, if I get what you really want you can try this:
SELECT DISTINCT order_id
FROM order_history A
INNER JOIN order_status B
ON A.order_status_id = B.order_status_id
WHERE (A.order_Status_id = '1' AND A.date_added < #date) AND (A.order_status_id = '3' AND A.date_added < #date)
SELECT h1.order_id
FROM order_history h1
JOIN order_status s1
ON s1.order_status_id = h1.order_status_id
JOIN order_history h2
ON h2.order_id = h1.order_id
JOIN order_status s2
ON s2.order_status_id = h2.order_status_id
WHERE h1.date_addded < '2014-04-01'
AND s1.name = 'received'
AND h2.date_addded >= '2014-04-01'
AND s2.name = 'shipped';
Note: Too many 'd's in addded
SELECT r.order_id
FROM (
SELECT DISTINCT oh.order_id
FROM order_history AS oh
JOIN order_status AS os ON(oh.order_status_id = os.order_status_id)
WHERE os.name = 'received'
AND oh.date_addded < '2014-04-01'
) AS r
JOIN (
SELECT DISTINCT oh.order_id
FROM order_history AS oh
JOIN order_status AS os ON(oh.order_status_id = os.order_status_id)
WHERE os.name = 'shipped'
AND oh.date_addded > '2014-04-01'
) AS s ON (s.order_id = r.order_id)
demo
What about this simple and light query:
SELECT DISTINCT order_id
FROM order_history o1
JOIN order_history o2
ON o1.order_id = o2.order_id
AND o1.order_status_id=1 AND o1.date_added<'2014-04-01'
AND o2.order_status_id=3 AND o2.date_added>'2014-04-01';
Not tested, but try this:
SELECT A.ORDER_ID
FROM ORDER_HISTORY A, ORDER_HISTORY B
WHERE A.ORDER_ID = B.ORDER_ID
AND A.order_status_id = 1
AND A.date_addded < TO_DATETO_DATE ('2014-04-01', 'YYYY-MM-DD')
AND B.order_status_id = 3
AND B.date_addded > TO_DATETO_DATE ('2014-04-01', 'YYYY-MM-DD');

MySQL - How to make more than 1 where clause on same column?

Well i'm trying to make a where clause on same column many times i.e:
product
----------------------------------------
| product_id | product_name | group_id |
----------------------------------------
group
-------------------------
| group_id | group_name |
-------------------------
group_val
-------------------------
| group_id | product_id |
-------------------------
select b.product_name
from group_val a
inner join product b using(product_id)
inner join group c using(group_id)
where a.group_id in(10,15,88)
group by b.product_id;
it's same as or ... or but i need to do something like: it only will return product that are on group 10 and group 15 and group 88: I mean that a product need to be in these 3 groups.
i.e:
group_val
-------------------------
| group_id | product_id |
-------------------------
| 10 | 1 |
-------------------------
| 15 | 1 |
-------------------------
| 88 | 1 |
-------------------------
| 15 | 2 |
-------------------------
| 10 | 2 |
-------------------------
In this case it will only return product 1
How can I do it?
Just working with your example query, and assuming that you explicity know, programmatically or otherwise, which group_ids you're looking to match and how many there are:
select `product_name`, count(gv.`product_id`) as cnt
from `product` p
left join `group_val` gv
on p.`product_id` = gv.`product_id`
where gv.`group_id` in (10, 15, 88)
group by p.`product_id`
having cnt = 3;
will select all the product_ids in group_val that is in all of those groups.
You don't need the field group_id in table product
SELECT p.product_name
FROM product AS p
INNER JOIN group_val AS g1 ON p.product_id = g1.product_id
INNER JOIN group_val AS g2 ON p.product_id = g2.product_id
INNER JOIN group_val AS g3 ON p.product_id = g3.product_id
WHERE g1.group_id = 10 AND g2.group_id = 15 AND g3.group_id=88;
Try it in SQL Fiddle