SQL: Sum factor*value in a LEFT JOIN - mysql

I would like to get some information: I got a table called "invoices" and a table called "invoice_positions".
All personal information about a customer are stored in "invoices". All positions are stored in "invoice_positions".
Well, now I would like to know the total sum of all matching positions:
I got this invoice-entry:
id: 1
customer: 4
I got this invoice-positions-entry:
id: 1
invoiceid: 1
factor: 2
value: 5
id: 2
invoiceid: 1
factor: 1
value: 5
The result should be: 2*5+1*5 = 15
This is my query so far:
SELECT DISTINCT a.*,SUM(ip.factor * ip.value) as totalsum,om.orderid,o.userid as userid,c.lastname as customer_lastname, c.firstname as customer_firstname, c.company as customer_company,uc.name AS editor,created_by.name AS created_by
FROM `o45_hero_invoices` AS a
LEFT JOIN o45_hero_invoices_positions AS ip ON ip.invoiceid=a.id
LEFT JOIN o45_hero_invoices_mapping AS om ON om.invoiceid=a.id
LEFT JOIN o45_hero_orders AS o ON o.id=om.orderid
LEFT JOIN o45_hero_customers AS c ON c.userid=o.userid
LEFT JOIN o45_users AS uc ON uc.id=a.checked_out
LEFT JOIN o45_users AS created_by ON created_by.id = a.created_by
WHERE (a.state IN (0, 1))
ORDER BY a.id asc
But my result is not 15 - it's 30.

you will no longer need the distinct with the group by.
a.* will have to be split into individual columns you want to return in results.
group by has been added below for known columns
.
SELECT a.*,SUM(ip.factor * ip.value) as totalsum,
om.orderid, o.userid as userid, c.lastname as customer_lastname,
c.firstname as customer_firstname, c.company as customer_company,
uc.name AS editor,
created_by.name AS created_by
FROM `o45_hero_invoices` AS a
LEFT JOIN o45_hero_invoices_positions AS ip ON ip.invoiceid=a.id
LEFT JOIN o45_hero_invoices_mapping AS om ON om.invoiceid=a.id
LEFT JOIN o45_hero_orders AS o ON o.id=om.orderid
LEFT JOIN o45_hero_customers AS c ON c.userid=o.userid
LEFT JOIN o45_users AS uc ON uc.id=a.checked_out
LEFT JOIN o45_users AS created_by ON created_by.id = a.created_by
WHERE (a.state IN (0, 1))
GROUP BY a.Field1, a.Field2, A.Field3...,
om.orderid, o.userid, c.lastname, c.firstname,
c.company, uc.name, created_by.name
ORDER BY a.id asc

Related

inner join 4 tables with group, order by, having clause

I have 4 table and i want to extract: id, nume, localitate, masina_id, nr_inmatriculare, an_fabricatie, rafinarie, marca, and sum (quantity+deliver_quantity) as total_quantity group by an_fabricatie , Order by marca, and put some having clouse.
I don’t know how to make this.
My query is as bellow , but I think isn't correct.
select c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.an_fabricatie,
i.rafinarie, m.marca from clienti c inner join livrari l on c.id = l.id inner join incarcari I on l.incarcare_id = l.livrari_id inner join masina m on i.id_marca = m.id, sum(select quantity, deliver_quantity) as total_quantity group by an_fabricatie having quantity >1000 order by marca;
Incarcari table
Id|livrari_id|id_marca|nr_inmatriculare|an_fabricatie|rafinarie|aviz_incarcare|quantity|
Livrari table
Id|masina_id|client_id|incarcare_id|deliver_quantity|aviz_livrare
Masini table
Id|numar_inmatriculare|marca|an_fabricatie|
Clienti table
Id|nume|localitate|date_add|date_upd|
SELECT c.id, c.nume, c.localitate, l.masina_id, i.nr_inmatriculare, i.an_fabricatie, i.rafinarie, m.marca, (SUM(i.quantity) + SUM(l.deliver_quantity)) AS total_quantity
FROM clienti c
INNER JOIN livrari l ON c.id = l.id
INNER JOIN incarcari i ON l.incarcare_id = i.livrari_id
INNER JOIN masini m ON i.id_marca = m.id
GROUP BY i.an_fabricatie, c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.rafinarie, m.marca
HAVING i.quantity > 1000
ORDER BY m.marca DESC;

choosing the sql statement which use less loading time

i have 2 sql statements which produce the same result, but wondering which one to choose?
lets say 1 have 3 tables:
supplier
supplier_status
supplier_contact
statement 1)
SELECT a.*, b.status_name
(SELECT c.name FROM contact c
WHERE c.supplier_id = a.supplier_id
ORDER BY c.contact_id DESC limit 1) AS contact_name
FROM supplier a LEFT JOIN supplier_status b
ON a.status_id = b.status_id
statement 2)
SELECT a.*, b.status_name, c.name AS contact_name
FROM supplier a LEFT JOIN supplier_status b
ON a.status_id = b.status_id
LEFT JOIN (SELECT name, supplier_id
FROM contact
ORDER BY contact_id DESC
) c ON a.supplier_id = c.supplier_id
GROUP BY a.supplier_id
Try this query:
SELECT a.*, b.status_name, c.name AS contact_name
FROM supplier a
LEFT JOIN supplier_status b ON a.status_id = b.status_id
LEFT JOIN contact c ON a.supplier_id = c.supplier_id
LEFT JOIN contact d ON c.supplier_id = d.supplier_id AND c.contact_id < d.contact_id
WHERE d.contact_id IS NULL
It's possible that it doesn't produce the same result as yours (I didn't test it) but if it does then all you have to do is to make sure the fields that appear in the JOIN conditions are indexed (they probably are FKs, so they already are).

mySQL Sub Select needed

I have three tables, libraryitems, copies and loans.
A libraryitem hasMany copies, and a copy hasMany loans.
I'm trying to get the latest loan entry for a copy only; The query below returns all loans for a given copy.
SELECT
libraryitems.title,
copies.id,
copies.qruuid,
loans.id AS loanid,
loans.status,
loans.byname,
loans.byemail,
loans.createdAt
FROM copies
INNER JOIN libraryitems ON copies.libraryitemid = libraryitems.id AND libraryitems.deletedAt IS NULL
LEFT OUTER JOIN loans ON copies.id = loans.copyid
WHERE copies.libraryitemid = 1
ORDER BY copies.id ASC, loans.createdAt DESC
I know there needs to be a sub select of some description in here, but struggling to get the correct syntax. How do I only return the latest, i.e MAX(loans.createdAt) row for each distinct copy? Just using group by copies.id returns the earliest, rather than latest entry.
Image example below:
in the subquery , getting maximum created time for a loan i.e. latest entry and joining back with loans to get other details.
SELECT
T.title,
T.id,
T.qruuid,
loans.id AS loanid,
loans.status,
loans.byname,
loans.byemail,
loans.createdAt
FROM
(
SELECT C.id, C.qruuid, L.title, MAX(LN.createdAt) as maxCreatedTime
FROM Copies C
INNER JOIN libraryitems L ON C.libraryitemid = L.id
AND L.deletedAt IS NULL
LEFT OUTER JOIN loans LN ON C.id = LN.copyid
GROUP BY C.id, C.qruuid, L.title) T
JOIN loans ON T.id = loans.copyid
AND T.maxCreatedTime = loans.createdAt
A self left join on loans table will give you latest loan of a copy, you may join the query to the other tables to fetch the desired output.
select * from loans A
left outer join loans B
on A.copyid = B.copyid and A.createdAt < B.createdAt
where B.createdAt is null;
This is your query with one simple modification -- table aliases to make it clearer.
SELECT li.title, c.id, c.qruuid,
l.id AS loanid, l.status, l.byname, l.byemail, l.createdAt
FROM copies c INNER JOIN
libraryitems li
ON c.libraryitemid = li.id AND
li.deletedAt IS NULL LEFT JOIN
loans l
ON c.id = l.copyid
WHERE c.libraryitemid = 1
ORDER BY c.id ASC, l.createdAt DESC ;
With this as a beginning let's think about what you need. You want the load with the latest createdAt date for each c.id. You can get this information with a subquery:
select l.copyid, max(createdAt)
from loans
group by l.copyId
Now, you just need to join this information back in:
SELECT li.title, c.id, c.qruuid,
l.id AS loanid, l.status, l.byname, l.byemail, l.createdAt
FROM copies c INNER JOIN
libraryitems li
ON c.libraryitemid = li.id AND
li.deletedAt IS NULL LEFT JOIN
loans l
ON c.id = l.copyid LEFT JOIN
(SELECT l.copyid, max(l.createdAt) as maxca
FROM loans
GROUP BY l.copyid
) lmax
ON l.copyId = lmax.copyId and l.createdAt = lmax.maxca
WHERE c.libraryitemid = 1
ORDER BY c.id ASC, l.createdAt DESC ;
This should give you the most recent record. And, the use of left join should keep all copies, even those that have never been leant.

Issue to get total amount while using inner join in MYSQL

I get an wrong TotalPrice from the ItemDetails table while join the taxdetails table.
Code 1:
select Distinct B.ID as BillId,
I.ID as ItemDetailId,
I.TotalPrice as ItemPrice,
T.Amount as TaxAmount from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id;
Refer below image,
While sum the TotalPrice and TotalTaxAmount on the same query i got an wrong TotalPrice result,
Code 2:
select Distinct B.ID as BillId,
SUM(I.TotalPrice) as TotalPrice,
SUM(T.Amount) as TotalTaxAmount from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id
group by B.ID;
Please refer below image,
Actual issue is as per taxdetails per itemdetail each row the rows become multiple so the totalprice get differs.
Expected Output for code 2 (i have listed the first row expected result) is,
Billid TotalPrice TotalTaxAmount
1 70 30
Try this,you have multiple items/bill, that is why you can't make inner join directly.Remove group by also.
select B.ID as BillId,
I.TotalPrice as TotalPrice,
T.Amount as TotalTaxAmount from Bill B
inner join
(
select BillNoID,SUM(TotalPrice) as TotalPrice from ItemDetails
group by BillNoID
)as I on I.BillNoID = B.ID
inner join
(
Select ItemDetailId,SUM(Amount) as Amount from TaxDetails
group by ItemDetailId
)as T on T.ItemDetailId = I.Id

Incorrect id returned on LEFT JOIN in Mysql statement

I need to get the id and timestamps of table sellers and all other columns (without knowing the column names) from these results returned from this MySql statement:
SELECT * FROM sellers a
LEFT JOIN users b ON a.user_id = b.id
LEFT JOIN country_types c ON a.country_type_id = c.id
LEFT JOIN language_types d ON a.language_type_id = d.id
WHERE a.email=?
The seller id though is incorrectly set because users, country_types, and language_types all have a value id. How can I set seller_id and seller_timestamp? I tried this but it is incorrect:
SELECT a.id seller_id, a.timestamp seller_timestamp, * FROM sellers a ...
You want this:
SELECT a.id as seller_id, a.timestamp as seller_timestamp, a.*, b.*, c.*, d.*
FROM sellers a
LEFT JOIN users b ON a.user_id = b.id
LEFT JOIN country_types c ON a.country_type_id = c.id
LEFT JOIN language_types d ON a.language_type_id = d.id
WHERE a.email=?
Im not sure but try alias, for example:
a.id AS seller_id
and etc.
In joins you can't select other columns in this way:
SELECT a.id seller_id, a.timestamp seller_timestamp, * FROM sellers a...
You need to write required column names.