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).
Related
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
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.
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.
Is it possible to INNER JOIN a MySQL query to achieve this result?
I have a table with Strategies and a table with Members. The Strategy table holds the ID of the author that corresponds to their ID in the Member table and the ID of an author that updated the existing author's work. Is it possible to grab a reference to both of these people at the same time? Something like the following, which returns no errors, but also no results...
SELECT * FROM Strategies
INNER JOIN Members AS a
INNER JOIN Members AS b
WHERE Strategies.ID='2'
AND Strategies.AuthorID = a.ID
AND Strategies.UpdateAuthorID = b.ID
Use a LEFT JOIN:
SELECT
s.*,
a.Name AS MemberName,
b.Name AS UpdatedMemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2 ;
If you want them in one column use COALESCE:
SELECT
s.*,
COALESCE(a.Name, b.Name) AS MemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2
SELECT toD.dom_url AS ToURL,
fromD.dom_url AS FromUrl,
rvw.*
FROM reviews AS rvw
LEFT JOIN domain AS toD
ON toD.Dom_ID = rvw.rev_dom_for
LEFT JOIN domain AS fromD
ON fromD.Dom_ID = rvw.rev_dom_from
if domain is table name
I'm not that into MySQL joins, so maybe you could give me a hand. I've got the following tables:
Table a
Fields ID,name
Table b
Fields aID,cID,ID,found
Table c
Fields ID,name
The result I want to get is the following: I want all the records where b.found = 1. Of these records I don't want a.id or a.name, but I want the number of records that would have been returned if I would have wanted so. So if there are five records that have b.found = 1 and c.id = (for example) 3, then I want a returned value of 5, c.id and c.name.
Someone is able to do this?
Actually this is what I want to get from the database:
A list of all records in table C and a count of records in table B that has found = 1 and b.c_id = c.id
Table: a
Fields: ID, name
Table: b
Fields: aID, cID, found
Table: c
Fields: ID, name
SELECT c.ID, c.name, COUNT(1)
FROM b
JOIN c ON c.ID = b.cID AND b.found=1
GROUP BY c.ID
SELECT c.id, c.name, COUNT(*)
FROM c
INNER JOIN b
ON c.id = b.c_id
AND b.found = 1
GROUP BY c.id, c.name
SELECT COUNT(*), c.id, c.name
FROM a, b, c
WHERE a.id = b.a.id AND c.id = b.a.id AND b.found = 1 AND c.id = idThatIAmSearchingFor
Apologies if I didn't get the syntax exact, but I believe that's the basic structure you want. The COUNT function returns the number of rows found by the query.
Something like:
SELECT count(`c`.*),
`c`.`id`,
`c`.`name`
FROM `b`
JOIN `c`
ON `c`.`id` = `b`.`c_id`
WHERE `b.found` = 1
I think this would provide the required output -
select count(*), b.cID, c.name from b
inner join c on c.id=b.cID and b.found=1
group by b.cID
SELECT COUNT(*) AS Count, c.id, c.name
FROM b join a on a.id = b.a_id
WHERE b.found = 1
GROUP BY c.Id;
COUNT returns count of records in each group from GROUP BY.