How to join multiple tables with multiple conditions - mysql

I have six tables
online_transaction
| date | id | supplier_id | product code |
online_transaction_enc
| date | id | item |
offline_transaction
| date | id |
offline_transaction_enc
| date | id | item |
products
| type | product_code |
supplier
| supplier_id | country |
Select count(item) where date is between '2018-Jun-01' And '2018-July-30' AND Type='household' AND country='Malaysia'
These is roughly what I want to achieve. I want to union item from online and offline on date and id so I will get all items combine and then followed by the other requirements.
How can do this in MySQL ?

Try this:
select count(a.item) from
(select date, id, item from online_transaction_enc
union
select date, id, item from offline_transaction_enc)a
inner join
(
select date,id,supplier_id,productcode from online_transaction
union
select date,id,supplier_id,productcode from offline_transaction)b
on a.date=b.date and a.id=b.id
inner join supplier on b.supplier_id=supplier.supplier_id
inner join products on b.productcode=products.product_code
where a.date between '20180601' And '20180730' AND Type='household' AND country='Malaysia'

SELECT count(item)
FROM online_transaction_enc
INNER JOIN online_transaction_enc ON supplier_id
INNER JOIN products ON supplier_id
...
WHERE WHERE (date BETWEEN '2010-01-30 14:15:55' AND '2010-09-29 10:15:55')
;
This solution is using an inner join. I believe this is what you're looking for. Here is more documentation
http://www.mysqltutorial.org/mysql-inner-join.aspx

Related

MySql query code to fetch unique data from single ID

How do i List the CUSTNUMs and NAMES of any customer who has only ordered chemical [NUMBER].
ORDERS TABLE
+---------+--------+------------+------+
| CUSTNUM | CHEMNO | DATE | QTY |
+---------+--------+------------+------+
| 123456 | 1234 | 2000-00-00 | 35 |
+---------+--------+------------+------+
CUSTOMER TABLE
+---------+-----------+-----------+
| CUSTNUM | NAME | LOCATION |
+---------+-----------+-----------+
| 123456 | AmChem | New York |
+---------+-----------+-----------+
You could join the CUSTOMER and ORDERS tables containing orders for a particular <chemno> with a subquery for the custnum that buy only a product:
SELECT
CUSTNUM, NAME
FROM
CUSTOMER c
INNER JOIN
ORDERS o ON o.CUSTNUM = c.CUSTNUM and o.CHEMNO = <chemno>
INNER JOIN
( SELECT
CUSTNUM
FROM
ORDERS
GROUP BY
CUSTNUM
HAVING
COUNT(DISTINCT CHEMNO) = 1 ) t ON t.CUSTNUM = o.CUSTNUM
I will approach this with one join between both tables, then grouping by the column CUSTNUM of the ORDERS table and finally adding the required conditions on the HAVING clause, like this:
SELECT
o.CUSTNUM,
c.NAME
FROM
ORDERS AS o
INNER JOIN
CUSTOMER AS c ON c.CUSTNUM = o.CUSTNUM
GROUP BY
o.CUSTNUM
HAVING
( COUNT(DISTINCT o.CHEMNO) = 1 AND MIN(o.CHEMNO) = <some_chemno> )
OK, slow day...
SELECT DISTINCT x.custnum
FROM orders x
LEFT
JOIN orders y
ON y.custnum = x.custnum
AND y.chemno <> x.chemno
WHERE x.chemno = 9377
AND y.order_id IS NULL;
The rest of this task has been left as an exercise for the reader

Match only if all elements of a column are in another table

I've made a little database in SQL that as 2 tables Product (Name, Ingredient and Available (Ingredient):
| Product | Available |
| Name | Ingredient | Ingredient |
| 1 | a | a |
| 1 | b | c |
| 2 | a |
| 2 | c |
I want the name of a product only if ALL its ingredients are inside the Available table.
For the previous example, the result should be: Product "2"
and not Product "1", because I don't have the ingredient "b" in the Available table.
Thanks for the help
You can try with left join (to figure out which Products don't have necessary Ingredients) and group by + having to filter Products that have at least one missing Ingredient:
select p.Name
from Products p
left join Available a on a.Ingredient = p.Ingredient
group by p.Name
having sum(a.Ingredient is null) = 0
You can try something like this also:
WITH TEMP_PRODUCTS AS
(
SELECT NAME, COUNT(1) AS NUMBER_OF_INGREDIENTS
FROM PRODUCT
GROUP BY PRODUCT
)
SELECT PRD.NAME, COUNT(1) AS NUMBER_OF_AVAILABLE_INGREDIENTS
FROM PRODUCT PRD
JOIN TEMP_PRODUCTS TMP ON PRD.NAME = TMP.NAME
WHERE EXISTS (SELECT 1
FROM INGREDIENT ING
WHERE ING.INGREDIENT = PRD.INGREDIENT)
GROUP BY PRD.NAME
HAVING COUNT(1) = TMP.NUMBER_OF_INGREDIENTS;

Joining multiple select sql statements (4 tables)

I need to join together 2 SQL statements and both of those statements work on their own. But I don't know how to combine both into 1 SQL statement.
I have two tables in 1st statement, TR120 and TR1201.
The SQL is this:
select
PRODUCT, PRICE, QUANTITY, INVOICE.DATE
from
TR1201
left join
(select
DATE, ID as INVOICE_ID, INVOICE
from TR120) as INVOICE on INVOICE.INVOICE_ID = ID
where
INVOICE.DATE >= '2016-06-01' and INVOICE.DATE <= '2016-06-30'
This returns a list of all the products I sold, with price, quantity and date of sales in a specific time frame from 01-06-16 till 30-06-16.
Now I need to find out the latest price that I bought product for in different two tables TR100 and TR1001 based on the product and date of sale from the 1st SQL statement.
select
PRODUCT, PRICE, SUP.DATE
from
TR1001
left join
(select
DATE, ID as SUP_ID, SUP_INVOICE
from TR100) as SUP on SUP.SUP_ID = ID
This returns a list of all the products that I have bought with a price and a date. I only need last record from this query based on product and date of purchased.
TR120
ID | INVOICE | DATE
1 | 000001 |2016-06-05
2 | 000002 |2016-06-15
3 | 000003 |2016-06-25
TR1201
ID | PRODUCT | PRICE A | QUANTITY
1 | A | 2,00 | 5
2 | A | 2,00 | 2
3 | A | 2,00 | 1
TR100
ID | SUP_INVOICE | DATE
1 | 160001 | 2016-05-30
2 | 160002 | 2016-06-16
TR1001
ID | PRODUCT | PRICE B
1 | A | 0,5
2 | A | 0,7
The result I am trying to get is this:
PRODUCT | PRICE A (tr1201) | QUANTITY | DATE (tr100) | PRICE B (tr1001)
A | 2 | 5 | 2016-05-30 | 0,5
A | 2 | 2 | 2016-05-15 | 0,5
A | 2 | 1 | 2016-05-16 | 0,7
That is all I want to do :(
Have you tried first_value?
FIRST_VALUE ( [scalar_expression ] )
OVER ( [ partition_by_clause ] order_by_clause [ rows_range_clause ] )
it works like this:
select distinct id,
first_value(price) over (partition by id (,sup) order by date DESC (latest, ASC for oldest)) as last_price
from table;
Documentation can be found here: https://msdn.microsoft.com/en-us/library/hh213018.aspx
I don't have your tables so cannot test and therefore am providing advice only.
I think what you need is an Outer apply like this instead of joins
select
T1.Product
, T1.Price
, T2.DATE -- Alias this
, T2.Price -- Alias this
, T3.DATE -- Alias this
, T3.Price -- Alias this
from T1
OUTER APPLY (
select top 1
Date
,Price
from table2
WHERE ID = T1.Id AND product = T1.Product-- plus any other joins
ORDER BY Date desc
) as T2
OUTER APPLY (
select top 1
Date
,Price
from table3
WHERE ID = T1.Id AND product = T1.Product-- plus any other joins
ORDER BY Date desc
) as T3

How to select the SUM of the multiplication of two different table fields specifying the value of other two fields?

Based on this table schema:
products
+----+------+-------+--------+--------------+-------+-------+------+-------+
| Id | Name | Price | Detail | Product_type | Image | Color | Size | Stock |
+----+------+-------+--------+--------------+-------+-------+------+-------+
order_details
+----+------------+--------+------+-------+----------+
| Id | Product_id | Amount | Size | Color | Order_id |
+----+------------+--------+------+-------+----------+
orders
+----+-----------+------------+----------+
| Id | Client_id | Date_start | Date_end |
+----+-----------+------------+----------+
How can I select the SUM() (if this function it's even necessary) of products.Price * order_details.Amount specifying the client and the order id?
I've tried with this query, among others:
SELECT SUM((SELECT pr.Price FROM products pr WHERE pr.Id = od.Product_id) * od.Amount) AS Total
FROM order_details od
WHERE (SELECT o.Client_id FROM orders o WHERE o.Id = $order) = $client
But it's returning a wrong result and I can't figure out how to do it. Also please note I want to use subqueries.
Thanks.
Dno't use a subselect, use a join:
SELECT orders.Id, SUM(products.Price * order_details.amount)
FROM orders
LEFT JOIN orders_details ON orders.Id = order_details.Order_id
LEFT JOIN products ON products.Id = order_details.Product_id
GROUP By orders.Clien_id, orders_details.Product_id

left join, return non matching rows, where clause on right table, group by

Sorry about the complicated title.
I have two tables, customers and orders:
customers - names may be duplicated, ids are unique:
name | cid
a | 1
a | 2
b | 3
b | 4
c | 5
orders - pid is unique, join on cid:
pid | cid | date
1 | 1 | 01/01/2012
2 | 1 | 01/01/2012
3 | 2 | 01/01/2012
4 | 3 | 01/01/2012
5 | 3 | 01/01/2012
6 | 3 | 01/01/2012
So I used this code to get a count:
select customers.name, orders.date, count(*) as count
from customers
left JOIN orders ON customers.cid = orders.cid
where date between '01/01/2012' and '02/02/2012'
group by name,date
which worked fine but didnt give me null rows when the cid of customers didnt match a cid in orders, e.g. name-c, id-5
select customers.name, orders.date, count(*) as count
from customers
left JOIN orders ON customers.cid = orders.cid
AND date between '01/01/2012' and '02/02/2012'
group by name,date
So I changed the where to apply to the join instead, which works fine, it gives me the null rows.
So in this example I would get:
name | date | count
a | 01/01/2012 | 3
b | null | 1
b | 01/01/2012 | 3
c | null | 1
But because names have different cid's it is giving me a null row even if the name itself does have rows in orders, which I don't want.
So I'm looking for a way for the null rows to only be returned when any other cid's that share the same name also do not have any rows in orders.
Thanks for any help.
---EDIT---
I have edited the counts for null rows, count never returns null but 1.
The result of
select * from (select customers.name, orders.date, count(*) as count
from customers
left JOIN orders ON customers.cid = orders.cid
AND date between '01/01/2012' and '02/02/2012'
group by name,date) as t1 group by name
is
name | date | count
a | 01/01/2012 | 3
b | null | 1
c | null | 1
First, select your date grouped by (name, date), excluding NULLs, then join with a set of distinct names:
SELECT names.name, grouped.date, grouped.count
FROM ( SELECT DISTINCT name FROM customers ) as names
LEFT JOIN (
SELECT customers.name, orders.date, COUNT(*) as count
FROM customers
LEFT JOIN orders ON customers.cid = orders.cid
WHERE date BETWEEN '01/01/2012' AND '02/02/2012'
GROUP BY name,date
) grouped
ON names.name = grouped.name
The best approach would be Group them together based on Cid's and then other parameters.
So you would get the proper output with NULL values based on Left Outer Join.