SQL query to get SUM from more dependent tables - mysql

I have the following MySQL DB structure:
table sales_order - id, name, ...
id | name
------------------
1 | Order Test
table sales_order_item - id, order_id, name, amount_dispatched ...
id | order_id | name | amount_dispatched
------------------------------------------
1 | 1 | Item 1 | 5
2 | 1 | Item 2 | 10
table sales_order_item_invoice - id, item_id, amount, ...
id | item_id | amount
---------------------
1 | 1 | 3
2 | 2 | 5
3 | 2 | 5
These three tables are in chain via the foreign keys. Table "invoice" can have more rows for one row in "item". Table "item" can have more rows for one row in "order".
Now, I need to create SQL query that returns all rows from table sales_order and appends there some data from the other tables - amount_dispatched and amount_invoiced:
dispatched = sum of all order's items' amount_dispatched
invoiced = sum of all invoices' amount (or 0 if no invoice exists)
Such query seems to be straightforward:
SELECT
`sales_order`.*,
SUM(`sales_order_item`.`amount_dispatched`) AS dispatched,
SUM(`sales_order_item_invoice`.`amount`) AS invoiced,
FROM `sales_order`
LEFT JOIN `sales_order_item` ON `sales_order`.`id` = `sales_order_item`.`order_id`
LEFT JOIN `sales_order_item_invoice` ON `sales_order_item`.`id` =`sales_order_item_invoice`.`item_id`
GROUP BY `sales_order`.`id`
The result contains all orders - ok
The result contains sum of invoices amount - ok
The result of "amount_dispatched" is invalid - if the item has more rows in item_invoice, the item's amount is summed several times, so for the example above, I get:
id | name | dispatched | invoiced
---------------------------------------
1 | Order Test | 25 | 13
Amount_dispatched is 25, but I would expect it to be 15.
Any idea how to correct my SQL query?
Thank you.

Firstly, use subquery do aggregation for invoice amount in sales_order_item_invoice, then left join.
SELECT
`sales_order`.*,
SUM(`sales_order_item`.`amount_dispatched`) AS dispatched,
SUM(t.`amount`) AS invoiced
FROM `sales_order`
LEFT JOIN `sales_order_item` ON `sales_order`.`id` = `sales_order_item`.`order_id`
LEFT JOIN (
SELECT item_id, SUM(amount) AS amount
FROM `sales_order_item_invoice`
GROUP BY item_id
) t ON `sales_order_item`.`id` = t.`item_id`
GROUP BY `sales_order`.`id`

Related

Find multiple totals by adding values from mysql table

I need to create a number adding all the values i can find in the db related to a specific customer.
Ex.
| Cust. | Value |
| 1 | 3 |
| 2 | 1 |
| 1 | 1 |
| 2 | 1 |
| 3 | 5 |
The result i want is : Customer #1 = 4, Customer #2 = 2; Customer #3 = 5.
There is a way to do that right into the mysql query?
Try Below query.
Select CONCAT('Customer #' , cust) as customer , sum(Value)
FROM customer_table
Group By cust
You want to SUM the values with a specific GROUP BY clause. Think of the GROUP BY as dividing rows into buckets and the SUM as aggregating the contents of those buckets into something useful.
Something like:
SELECT SUM(Value) FROM table GROUP BY Cust

MySQL Error to selecting data

I have two column one column associated with another...
Table:base_data
id |---name----|-----des
1 | some name1 | The description1
2 | some name2 | The description2
Table: photos
id |---p_id----|-----photo
1 | 1 | img1s.jpg
2 | 1 | img1w.jpg
3 | 2 | img2.jpg
4 | 2 | img14.jpg
5 | 2 | img15.jpg
I want to select all data from table 1(base_data) and one row from associated row from photos: table how can I do that ????
I don't want to select by greatest n per group I want to select all data from the first table and only one row of the second table which matches with the first table row id, just first match not other.
The Result I want...
id |---name----|---des----|---p_id----|---photo----|
1 | some name |the des..1| 1 | img1s.jpg|
2 | some name |the des..2| 2 | img2.jpg|
I suppose you want to associate base_data with the first photo taken, which should be the one with the lowest photos.id. In MySQL, you could write this as follows: Create an intermediate query which gives - for any p_id - the corresponding record with the lowest id. Then, left join base_data with this intermediate query result. Hope there are not to many typos in it :-) :
select b.id, p2.photo
from base_data b left join
(select p.photo, p.p_id, min(id) from photos p group by p.p_id) p2 on b.id = p2.p_id
If you want the alphanumerically lowest photo name, in MySQL you can do this:
select
t1.*,
t2.photo
from
base_data as t1
left join (
select
p_id,
min(photo) as photo
from
photos
group by
p_id
) as t2 on t2.p_id = t1.id;

MySQL insert multiple row select in other table

I have small database with couple of tables for some small PHP project. One of my SELECTs (given bellow table) gives result like this:
+-------+------+------+
| idpart | qty |IMEI |
+-------+------+------+
| 2 | 4 | xxx |
| 6 | 1 | yyyy |
| 8 | 2 | zzzz |
|10 | 3 | ssss |
+-------+------+------+
Number of rows changes it can be 1 or n, but its never less then 1. idpart is not repeating it self as result of this query - it can be show only once. This is the actual query:
select odel_part.idpart as idpart, model_part.qtyused as qty, reparationorders.IMEI as IMEI
from reparation orders
inner join order model on order_model.idreparationorder=reparationorders.idreparationorder
inner join models on order_model.idmodel = models.idmodel
inner join model_part on models.idmodel = model_part.idmodel
inner join parts on model_part.idpart = parts.idpart
where reparationorders.idreparationorder = 1
Result of this query along with some additional data which is fixed has to be inserted in to other table. Other table has following fields:
+-----------+-----------+-------+--------+-----+-------+
| idtrans | idpart | qty | date | tt | IMEI |
+-----------+-----------+-------+--------+-----+-------+
idtrans - int which autoincrements
idpart - from query (idpart)
qty - from query (qty)
date - entered manualy
tt - entered manualy
IMEI - from query (IMEI)
in this 2nd table idtrans is unique, idpart can repeat it self thorough rows (this is intended behaviour, because this table will track usage of this parts for different dates).
Can you help me with doing this insert to 2nd table (name of 2nd table is transactions)?
Thank you in advance
You would just do:
insert into transactions(idpart, qty, date, tt, IMEI)
select idpart, qty, now(), #tt, imei
from reparations orders . . .;
The . . . is just the rest of your query. I am guessing that you want the current date/time inserted for "date"; now() provides that information.

LEFT JOIN to newest row

I'm trying to get data from one table with additional data from second, but in second table i have many records connected to records in first table and I want take newest.
In first table i keep products and i second i keep prices with data. I want take products with actual(newest) price.
Products table:
ID | NAME
---+----------
1 | "jacket"
2 | "pants"
Prices table:
ID | PRODUCT_ID | DATE | PRICE
---+------------+------------+-------
1 | 1 | 2015-05-12 | 200
2 | 1 | 2015-07-12 | 100
3 | 2 | 2015-03-12 | 60
4 | 2 | 2015-08-12 | 90
Expected result:
1, "jacket", 100
2, "pants", 90
How can I do this?
Actually i've found solution - but with 2 subqueries. Doesn't look so good.
Find the max date for each price and then inner join with the rest of the tables.
SQL Fiddle
SELECT aa.id, aa.name, bb.price
FROM products AS aa
INNER JOIN prices AS bb
ON aa.id = bb.product_id
INNER JOIN (
SELECT product_id, MAX(date) AS max_date
FROM prices AS cc
GROUP BY product_id
) AS _aa
ON aa.id = _aa.product_id
WHERE bb.date = _aa.max_date;

MySQL: select table records where related table has empty match

I have two tables with related information. "RoodCMS_prodQuants" and "RoodCMS_albums". These look as follows:
RoodCMS_prodQuants:
This table is a product quantity table. The combination idnr-prodID is unique. idnr refers the ID of an order in another table, prodID refers to idnr in "RoodCMS_albums"
-------------------------------------------------
idnr | prodID | kwantiteit
------------------------------------------------
2 | 2 | 2
3 | 1 | 1
4 | 1 | 2
4 | 2 | 2
5 | 3 | 1
RoodCMS_albums:
For administrative purposes, I only delete a record here if it is flagged as "to-be-deleted" (gepubliceerd = '-1'), and if there are no entries related to it anymore in the previous table (records from RoodCMS_prodQuants with the prodID as idnr in RoodCMS_albums). That's because I'd like to keep information like price, name until the last order containing this product is deleted.
-------------------------------------------------------------------
idnr | gepubliceerd | ... name, price, quantity-in-stock, etc...
-------------------------------------------------------------------
2 | 1 |
3 | 1 |
4 | -1 | <---- this one is flagged to be deleted
1 | 1 |
In this case, I want to select the idnr of each record that does not have any corresponding records under the same prodID. For the tables that I displayed here, that means idnr='4' is a candidate to be selected, as there is no record with prodID='4'.
I tried a couple of queries to collect the records that match my criteria.
SELECT r1.idnr
FROM RoodCMS_albums AS r1, RoodCMS_prodQuants AS r2
WHERE r1.gepubliceerd='-1' AND r1.idnr = r2.prodID
GROUP BY r1.idnr HAVING SUM(r1.kwantiteit) = 0
... and:
SELECT r1.idnr
FROM RoodCMS_albums AS r1, RoodCMS_prodQuants AS r2
WHERE r1.gepubliceerd='-1' AND r1.idnr = r2.prodID
GROUP BY r1.idnr HAVING COUNT(r2.prodID) = 0
Both return an empty set of rows, whereas I aim for selecting idnr='4' from RoodCMS_albums. Could someone help me with writing a query that does return the result I aim for?
Thanks in advance!
You want a left outer join (or not in or not exists). You should learn to use proper, explicit join syntax -- such habits would help you when you encounter an issue like this. The query is more like:
SELECT r1.idnr
FROM RoodCMS_albums r1 LEFT JOIN
RoodCMS_prodQuants r2
ON r1.idnr = r2.prodID
WHERE r1.gepubliceerd = '-1' and r2.ProdId is NULL;