I am having an issue where I want to join several columns by an id.
My first table looks like this:
submitter_id reviewer_id processor_id
75 34 91
The table that I want to join looks like this:
id first_name last_name
75 Bob Smith
34 Albert McDonald
91 Joe Blo
I am trying to create a query that will look at each id in my first table and then get the first and last name's for each id.
For example, a query that does this should return something like:
[
75 => "Bob Smith",
34 => "Albert McDonald",
91 => "Joe Blo"
];
Can anybody help me construct a query that can accomplish this? Thanks!
Join the same table 3 times with different alias names
select t1.submitter_id, t1.reviewer_id, t1.processor_id,
t2.first_name as submitter_firstname, t2.last_name as submitter_lastname,
t3.first_name as reviewer_firstname, t3.last_name as reviewer_lastname,
t4.first_name as processor_firstname, t4.last_name as processor_lastname
from firstTable t1
left join namesTable t2 on t1.submitter_id = t2.id
left join namesTable t3 on t1.reviewer_id = t3.id
left join namesTable t4 on t1.processor_id = t4.id
I think what your actually looking for is more like this:
SELECT n.id, CONCAT(n.first_name, ' ', n.last_name)
FROM names n
JOIN ids i
ON n.id = i.submitter_id
OR n.id = i.reviewer_id
OR n.id = i.processor_id
GROUP BY n.id;
This is only doing one join, shows the records with the 2 columns you actually want and restricts so users are only listed 1 time. Also since you probably don't want to return just the ID if the user doesn't have a name setup you don't want a left join.
Edit:
If you need indexes you can make one on submitter_id, reviewer_id, processor_id if the performance is needed for you.
You want all in one resultset, so you could use UNION ALL:
SELECT p.id, CONCAT(p.first_name, ' ', p.last_name) as name
FROM person p
JOIN firstTable f
ON p.id = f.submitter_id
UNION ALL
SELECT p.id, CONCAT(p.first_name, ' ', p.last_name) as name
FROM person p
JOIN firstTable f
ON p.id = f.reviewer_id
UNION ALL
SELECT p.id, CONCAT(p.first_name, ' ', p.last_name) as name
FROM person p
JOIN firstTable f
ON p.id = f.processor_id
I think this is a better approach if you plan to use some conditions only for some group, like where reviewer_id > 100. If not, the Sir. Egole is cleaner.
Assuming that you need one row in the first table to return one row at the result.
SELECT tt.submitter_id , CONCAT(ta.first_name, ' ', ta.last_name) ,
tt.reviewer_id , CONCAT(tb.first_name, ' ', tb.last_name) ,
tt.processor_id , CONCAT(tc.first_name, ' ', tc.last_name)
FROM `transaction` as tt , `names` as ta , `names` as tb , `names` as tc
WHERE tt.submitter_id = ta.id AND
tt.reviewer_id = tb.id AND
tt.processor_id = tc.id
The result would be the 3 ids with the corresponding names in one row per transaction.
Related
I have this query that works as I need. However I would like to have a column showing number of times a record repeats.
The query:
SELECT total.Total, subqry.Company AS Supplier, company.Company AS Customer, purchase_details.CompanyID,
product.Description1, purchase_details.PurchaseID, purchase_details.PurchaseCreated,
purchase_details.Completed, purchase_details.OriginalOrd
FROM purchase_details
LEFT JOIN product ON purchase_details.PartNumber = product.PartNumber
LEFT JOIN orders ON purchase_details.OriginalOrd = orders.OrderID
LEFT JOIN contact ON orders.ContactLinkID = contact.ID
LEFT JOIN company ON contact.LinkID = company.LinkID
LEFT JOIN (SELECT company.Company, purchase_details.CompanyID FROM company
LEFT JOIN purchase_details ON company.ID = purchase_details.CompanyID)
AS subqry ON purchase_details.CompanyID = subqry.CompanyID
LEFT JOIN (SELECT OriginalOrd, count(DISTINCT CompanyID) AS Total FROM purchase_details
GROUP BY OriginalOrd) AS total ON purchase_details.OriginalOrd = total.OriginalOrd
WHERE purchase_details.Completed = $show AND
(subqry.Company LIKE :search
OR company.Company LIKE :search
OR product.Description1 LIKE :search
OR purchase_details.PartNumber LIKE :search
OR purchase_details.PurchaseID LIKE :search
OR purchase_details.OriginalOrd LIKE :search)
GROUP BY PurchaseID
The company id column returns:
504
1739
504
1389
504
I would like to return the info below so ideally in a join:
504 | 3
1739 | 1
504 | 3
1389 | 1
504 | 3
I will use this column in the php application to trigger other functions.
Thanks in advance
Add company_id to the GROUp BY list after PurchaseID and add another column count(DISTINCT company_id) company_count to the select.
SELECT
....//other columns
count(DISTINCT purchase_details.CompanyID) company_count
FROM
...//rest of queries
GROUP BY purchase_details.CompanyID,PurchaseID
;
This bit looks odd...
SELECT c.Company
, pd.CompanyID
FROM company c
LEFT
JOIN purchase_details pd
ON c.ID = pd.CompanyID
You're selecting no information from purchase_details that's not already present in company. So why bother?
Also, what might ":search" actually look like?
use group by company_id
select count(company_id) as c
from table_name
group by company_id;
I have 3 tables.
First table keeps "group_names" with id numbers. Second table keeps "groups_elements" with id numbers and group_id numbers next to element_name. Third table keeps relations between group_elements which includes element_id, sub_element_id.
I wish to get concat group_name, element_name and element_id numbers sub_elements numbers.
Here is sqlfiddler link http://sqlfiddle.com/#!2/44f63
And i wish to get such result:
Solid Soil 5,6,7
Liquid Oil 8,9,10
I am using MySQL and PHP.
You can do so
SELECT CONCAT(g.group_name,' , ',e.element_name)
, GROUP_CONCAT(DISTINCT er.sub_element_id)
FROM groups g
JOIN elements e ON(g.id = e.group_id)
JOIN element_subelement_relation er ON(er.element_id= e.id)
GROUP BY g.group_name, e.element_name
Demo
Edit from comments
SELECT CONCAT(g.group_name,' , ',e.element_name) `group_elements`
, GROUP_CONCAT(DISTINCT er.`sub_element_id`) `ids`
FROM groups g
LEFT JOIN elements e ON(g.id = e.group_id)
LEFT JOIN element_subelement_relation er ON(er.element_id= e.id)
GROUP BY g.group_name, e.element_name
HAVING group_elements IS NOT NULL
ORDER BY g.group_name
Demo
using group_concat()
SELECT g.group_name, group_concat(sub_element_id) as items
FROM elements e INNER JOIN element_subelement_relation er
ON e.id = er.element_id INNER JOIN groups g
ON g.id = e.group_id
GROUP BY g.group_name
demo: http://sqlfiddle.com/#!2/44f63/21
Simply join and use group_concat on the sub ids:
select
concat(g.group_name, ' ', e.element_name) as name,
group_concat(sub_element_id order by sub_element_id) as sub_elements
from elements e
inner join groups g on g.id = e.group_id
inner join element_subelement_relation r on r.element_id = e.id
group by name
order by sub_elements, name;
The SQL fiddle: http://sqlfiddle.com/#!2/44f63/31.
You may also want to try these:
SELECT g.group_name, e.element_name, concat(g.id,",", e.id,",",esr.id) as ID
FROM element_subelement_relation esr
LEFT JOIN elements e ON(esr.element_id = e.id)
LEFT JOIN groups g ON(e.group_id = g.id)
I have 4 tables ACCOUNTS_TABLE , LINKS_TABLE, GROUPS_TABLE, KEYS_TABLE
I need to get all accounts details which is of acct_type xx with count of Links, groups& keywords . I have tried this query but it gives all count as 0
SELECT
acc.acct_id, acc.acct_type, count(link.id) as link_count, link.account,
groups.camp_id, count(groups.id) as group_count, count(keyword.key_id) as key_count
FROM ".ACCOUNTS_TABLE." as acc
LEFT JOIN ".LINKS_TABLE." as link ON link.account=acc.acct_id AND acct_type='xx'
LEFT JOIN ".GROUPS_TABLE." as groups ON groups.camp_id=link.id
LEFT JOIN ".KEYS_TABLE." as keyword ON keyword.camp_id=link.id
GROUP BY acc.acct_id
My required output should be like this
Any one please help me to slove this problem
You probably should use COUNT(DISTINCT ....).
SELECT acc.acct_id, COUNT(DISTINCT link.id), COUNT(DISTINCT groups.id), COUNT(DISTINCT keyword.key_id)
FROM ACCOUNTS_TABLE acc
LEFT OUTER JOIN LINKS_TABLE link ON link.account = acc.acct_id AND acct_type = 'advertiser'
LEFT OUTER JOIN GROUPS_TABLE groups ON groups.camp_id = link.id
LEFT JOIN KEYS_TABLE keyword ON keyword.id = link.id
WHERE acc.acct_type = 'xx'
GROUP BY acc.acct_id
EDIT
Amended to use the updated join conditions, etc:-
SELECT acc.acct_id, acc.acct_type, COUNT( DISTINCT link.id ) , COUNT( DISTINCT groups.id ) , COUNT( DISTINCT keyword.key_id )
FROM ACCOUNTS_TABLE acc
LEFT OUTER JOIN LINKS_TABLE link ON link.account = acc.acct_id
LEFT OUTER JOIN GROUPS_TABLE groups ON groups.camp_id = link.id
LEFT JOIN KEYS_TABLE keyword ON keyword.camp_id=link.id
WHERE acc.acct_type = 'xx'
GROUP BY acc.acct_id, acc.acct_type
You could try something like this:
SELECT ACC.Id
,( SELECT COUNT (*) FROM Links L WHERE L.AccountId = ACC.Id ) AS CountOfLinks
,( SELECT COUNT (*) FROM Groups G WHERE G.AccountId = ACC.Id ) AS CountOfGroups
FROM ( SELECT Id FROM Accounts Acc WHERE Acc.Type = 'some type' ) ACC
I've rejigged your code a bit (see below) for a few reasons:
It's helpful (for me anyway) to write my SELECT statements always in a certain way - with anything that is not being grouped placed first, and ideally putting things in same order as my JOINs and doing the same in my GROUP BY
I put anything which restricts my FROM table into the WHERE not the JOIN to make it clearer what I'm trying to do and also to make it easier to modify later on.
I also like to ensure it's well laid out to make it easier to scan for issues.
Take this rearranged query and read through it to make sure you are getting the behaviour you're expecting.
PS I'm not sure about your table names and quotation style - I usually use back ticks (`) and would never put dots (.) in my table names. If you put these in as placeholders that's fine but they could lead to trouble for you if they are real.
SELECT
acc.acct_id,
-- if you don't group by these then you need to remove them as they will just return the first values based on mysql behaviour
acc.acct_type,
link.account,
groups.camp_id,
-- these counts will only count where an ID is present which seems like what you're after
count(link.id) as link_count,
count(groups.id) as group_count,
count(keyword.key_id) as key_count
FROM ".ACCOUNTS_TABLE." as acc
LEFT JOIN ".LINKS_TABLE." as link ON link.account=acc.acct_id
LEFT JOIN ".GROUPS_TABLE." as groups ON groups.camp_id=link.id
LEFT JOIN ".KEYS_TABLE." as keyword ON keyword.id=link.id
WHERE acct_type='advertiser'
GROUP BY acc.acct_id,
-- only use these if you intend to group by them
acc.acct_type,
link.account,
groups.camp_id DESC
SELECT acct_type,
count(acct_type),
count(l.id),
count(g.id),
count(key_id)
FROM accounts a
LEFT JOIN links l ON (l.account = a.acct_id)
LEFT JOIN groups g ON (g.camp_id = l.id)
LEFT JOIN keysTable k ON k.group_id = g.id
GROUP BY acct_type HAVING acct_type = 'xx';
SQL Fiddle Validated: http://www.sqlfiddle.com/#!2/f4b6a/20
SELECT
accounts_table.acct_id,
accounts_table.acct_type,
COUNT(DISTINCT links_table.id) AS link_count,
COUNT(DISTINCT groups_table.id) AS group_count,
COUNT(DISTINCT keys_table.key_id) AS key_count
FROM
accounts_table
LEFT JOIN
links_table
ON links_table.account = accounts_table.acct_id
LEFT JOIN
groups_table
ON groups_table.camp_id = links_table.id
LEFT JOIN
keys_table
ON keys_table.camp_id = links_table.id
WHERE
acct_type = 'xx'
GROUP BY
accounts_table.acct_id,
accounts_table.acct_type
ORDER BY
link_count DESC,
group_count DESC,
key_count DESC
Edited answer to match updated question - this should do what you've asked for.
This should do what you've asked for, SQL fiddle here - http://www.sqlfiddle.com/#!2/f4b6a/20
I currently have this left join as part of a query:
LEFT JOIN movies t3 ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The trouble is that if there are several movies with the same name and same popularity (don't ask, it just is that way :-) ) then duplicate results are returned.
All that to say, I would like to limit the result of the left join to one.
I tried this:
LEFT JOIN
(SELECT t3.movie_name FROM movies t3 WHERE t3.popularity = 0 LIMIT 1)
ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The second query dies with the error:
Every derived table must have its own alias
I know what I'm asking is slightly vague since I'm not providing the full query, but is what I'm asking generally possible?
The error is clear -- you just need to create an alias for the subquery following its closing ) and use it in your ON clause since every table, derived or real, must have its own identifier. Then, you'll need to include movie_id in the subquery's select list to be able to join on it. Since the subquery already includes WHERE popularity = 0, you don't need to include it in the join's ON clause.
LEFT JOIN (
SELECT
movie_id,
movie_name
FROM movies
WHERE popularity = 0
ORDER BY movie_name
LIMIT 1
) the_alias ON t1.movie_id = the_alias.movie_id
If you are using one of these columns in the outer SELECT, reference it via the_alias.movie_name for example.
Update after understanding the requirement better:
To get one per group to join against, you can use an aggregate MAX() or MIN() on the movie_id and group it in the subquery. No subquery LIMIT is then necessary -- you'll receive the first movie_id per name withMIN() or the last with MAX().
LEFT JOIN (
SELECT
movie_name,
MIN(movie_id) AS movie_id
FROM movies
WHERE popularity = 0
GROUP BY movie_name
) the_alias ON t1.movie_id = the_alias.movie_id
LEFT JOIN movies as m ON m.id = (
SELECT id FROM movies mm WHERE mm.movie_id = t1.movie_id
ORDER BY mm.id DESC
LIMIT 1
)
you could try to add GROUP BY t3.movie_id to the first query
Try this:
LEFT JOIN
(
SELECT t3.movie_name, t3.popularity
FROM movies t3 WHERE t3.popularity = 0 LIMIT 1
) XX
ON t1.movie_id = XX.movie_id AND XX.popularity = 0
On MySQL 5.7+ use ANY_VALUE & GROUP_BY:
SELECT t1.id,t1.movie_name, ANY_VALUE(t3.popularity) popularity
FROM t1
LEFT JOIN t3 ON (t3.movie_id=t1.movie_id AND t3.popularity=0)
GROUP BY t1.id
more info
LEFT JOIN only first row
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Easy solution to left join the 1 most/least recent row is using select over ON phrase
SELECT A.ID, A.Name, B.Content
FROM A
LEFT JOIN B
ON A.id = (SELECT MAX(id) FROM B WHERE id = A.id)
Where A.id is the auto-incremental primary key.
LEFT JOIN (
SELECT id,movie_name FROM movies GROUP BY id
) as m ON (
m.id = x.id
)
// Mysql
SELECT SUM(db.item_sales_nsv) as total FROM app_product_hqsales_otc as db
LEFT JOIN app_item_target_otc as it ON
db.id = (SELECT MAX(id) FROM app_item_target_otc as ot WHERE id = db.id)
and db.head_quarter = it.hqcode
AND db.aaina_item_code = it.aaina_item_code AND db.month = it.month
AND db.year = it.year
WHERE db.head_quarter = 'WIN001' AND db.month = '5' AND db.year = '2022' AND db.status = '1'
I have 3 tables, 'u' 'd' 's'
'u' has
userid
divid
'd' has
divid
divname
's' has
sname
primaryuserid
secondaryuserid
Now what I'd like to do is display a table with rows of the following format
userid, divname, sname
Plus figure out a way to decipher whether userid is a primary or secondary for this sname table.
I'm able to show userid and divname using a left join, but I don't know how I would add a third table? To make it trickier, there can be more than 1 snames for each userid, up to ~20. Is there a way to display 0-20 snames depending on the userid, separated with commas?
What I have currently is just and u and d tables corresponding to each other.
SELECT
e.userid,
e.divid,
d.divname
FROM
e
LEFT JOIN d ON (e.divid = d.id)
ORDER BY e.userid
You're looking for a couple of different things here. First of all, the "way to display 0-20 snames depending on the userid, separated with commas" can be done with MySQL's GROUP_CONCAT() function, so your query would look like this (no distinction between primary and secondary yet):
SELECT u.userid,
d.divname,
GROUP_CONCAT(s.sname SEPARATOR ', ') AS "snames"
FROM u
LEFT JOIN d ON d.divid = u.divid
LEFT JOIN s ON (s.primaryuserid = u.userid OR s.secondaryuserid = u.userid);
Now, to be able to distinguish whether the user is primary or secondary, you have to get a little fancier. I'd probably do it with a union, like this:
SELECT u.userid,
d.divname,
GROUP_CONCAT(s.sname SEPARATOR ', ') AS "snames",
'Primary' AS "category"
FROM u
LEFT JOIN d ON d.divid = u.divid
LEFT JOIN s ON s.primaryuserid = u.userid
UNION ALL
SELECT u.userid,
d.divname,
GROUP_CONCAT(s.sname SEPARATOR ', ') AS "snames",
'Secondary' AS "category"
FROM u
LEFT JOIN d ON d.divid = u.divid
LEFT JOIN s ON s.secondaryuserid = u.userid
This will give you two rows (one Primary, one Secondary) for each userid with comma-separated lists of the snames.
You can join the tables, and s twice for the two possible relations:
select
u.userid
, d.divname
, coalesce(s1.sname, s2.sname)
, case when s1.sname is not null then 'Primary'
when s2.sname is not null then 'Secondary'
else 'None' end
from u
join d on d.divid = u.divid
left join s s1 on s1.primaryuserid = u.userid
left join s s2 on s2.secondaryuserid = u.userid
Displaying up to 20 usernames separated by comma's is best done on the client side, in PHP. It is possible to do it in the database, but the method depends on your DBMS. For MySQL, limiting a subquery to 20 rows is hard, but creating comma-separated lists is easy. For example:
select
group_concat(coalesce(s1.sname,s2.sname) separator ',')
, ...
from u
...
group by u.userid
Create a Inner Join and put it in a view. Then we can just do a select on the view.