My tables
product
pid name
1 AA
2 bb
3 cc
History table
hid pid uid
1 1 1
2 1 2
3 1 1 // this one should join with pid 1
4 3 2 // this one should join with pid 3
5 2 3
6 2 1 // this one should join with pid 2
I like to display most recent bidder on a product.The history tables stores bidder
details.if no bid on product just need to return null.
Thanks
How about something like
SELECT *
FROM product p LEFT JOIN
(
SELECT ht.*
FROM History_table ht INNER JOIN
(
SELECT pid,
MAX(hid) last_hid
FROM History_table ht
GROUP BY pid
) lstItem ON ht.pid = lstItem.pid
AND ht.hid = lstItem.last_hid
) ht ON p.pid = ht.pid
First you need to retrieve the MAX hid per pid, which by definition should be the most recent entry.
Then join that back to the same history table to retrieve the uid.
And lastly join this (LEFT JOIN) back to the actual products table.
Hope that helps.
Related
I'm struggling to get my head around MySQL joins. I have three tables
-- events
id name
1 Event 1
2 Event 2
-- registrations
id event name
1 1 Alice
2 1 Bob
3 2 Alice
4 2 Charlie
-- scores
id event name score
1 1 Alice 10
2 1 Charlie 20
3 2 Alice 15
4 2 Bob 30
For each event I'm trying to work out
How many people registered (rows in registration table) but did NOT get a score (exclude rows in scores table)
How many people got a score (rows in scores table) but did NOT register (exclude rows in registration table)
How many people BOTH registered and got a score
I've tried different variations of
SELECT *
FROM registrations r
LEFT JOIN scores s
ON r.event = s.event
WHERE s.event IS NULL
AND r.event = 1
but I'm not sure what I should be joining on: event or name but neither are null and I never seem to get the correct numbers I'm looking for. The result at the end should be like
name reg_only score_only reg&score total
event Event 1 1 1 1 3
You can use below 3 queries in same sequence as you mentioned in your query-
SELECT e.id, e.name, COUNT(r.id) AS registered_user
FROM `events` AS e
INNER JOIN registrations AS r ON e.id=r.event
LEFT JOIN scores AS s ON e.id = s.event
WHERE s.event IS NULL;
SELECT e.id, e.name, COUNT(r.id) AS scored_user
FROM `events`scores AS e
INNER JOIN scores AS s ON e.id=s.event
LEFT JOIN registrations AS r ON e.id = r.event
WHERE r.event IS NULL;
SELECT e.id, e.name, COUNT(*) AS both_user
FROM `events` AS e
INNER JOIN registrations AS r ON e.id=r.event
INNER JOIN scores AS s ON e.id = s.event;
I'm trying to create a query which selects from three tables.
m_release
---------------------------
release_id name
---------------------------
1 release1
2 release2
3 release3
mk_release_artist
---------------------------
release_id artist_id
---------------------------
1 134
2 135
mk_release_remix
---------------------------
release_id artist_id
---------------------------
3 134
I've created the following query so far, but it doesn't return any rows:
SELECT * FROM m_release A
JOIN mk_release_artist B ON A.release_id = B.release_id AND B.artist_id = 134
JOIN mk_release_remix C ON A.release_id = C.release_id AND C.artist_id = 134
It is working when i'm selecting from two tables using one JOIN
SELECT * FROM m_release A
JOIN mk_release_artist B ON A.release_id = B.release_id AND B.artist_id = 134
The output i'm expecting to see is:
---------------------------
release_id name
---------------------------
1 release1
3 release3
SELECT A.*
FROM m_release A
LEFT JOIN mk_release_artist B ON A.release_id = B.release_id
LEFT JOIN mk_release_remix C ON A.release_id = C.release_id
WHERE 134 in (B.artist_id, C.artist_id)
So, in B, author_id is the author, while in C, it's the remixer. Then your query selects entries where BOTH the author and the remixer are the id=134. Which has no matching entries in your example.
The juergen d's query would select entries where either author or the remixer is the id. Since it uses LEFT JOINs, it will even get the releases that have no corresponding entry in either B or C (the corresponding columns will be NULL).
I have six tables- Project,Equipment,Fish,Staff and the junction tables - Project_Equipment,Project_Fish and Project_Staff.I want to retrieve Project total cost.
So, I wrote the statement like follows,
SELECT P.ProjectID, (SUM(E.EquipPrice*PE.EQuantity)+SUM(F.FishPrice*PF.FQuantity)+SUM(PS.Salary)) as ProjectCost
FROM Equipment as E INNER JOIN Project_Equipment as PE
ON E.EquipID=PE.EquipID
INNER JOIN Project as P
ON PE.ProjectID=P.ProjectID
INNER JOIN Project_Fish as PF
ON P.ProjectID=PF.ProjectID
INNER JOIN Fish as F
ON PF.FishID=F.FishID
INNER JOIN Project_Staff as PS
ON P.ProjectID=PS.ProjectID
INNER JOIN Staff as S
PS.StaffID=S.StaffID
GROUP BY ProjectID
But, I got the price with twice of correct amount.
Your query will end up with a lot of duplicate results. Consider the following simpler case:
Table: Project
ProjectID EQuantity
1 1
2 1
Table: Equipment
EquipID EPrice
1 1
2 1
Table: Fish
FishID
1
2
Table: Project_Equipment
ProjectID EquipID
1 1
1 2
2 1
2 2
Table: Project_Fish
ProjectID FishID
1 1
1 2
2 1
2 2
Now, let's look at the results of a Project_Equipment query only:
SELECT p.projectid, e.eprice, pe.equantity FROM project p
INNER JOIN project_equipment pe ON pe.projectid=p.projectid
INNER JOIN equipment e ON e.equipid=pe.equipid
ProjectID EPrice EQuantity
1 1 1 // a
1 1 1 // b
2 1 1 // c
2 1 1 // d
That's as expected; a list of the price and quantity of each piece of equipment used by each project. But what do you think will happen when we INNER JOIN that to project_fish? That first result has project 1 in it twice, and project 2 in it twice, so we end up with every combination of that result and project_fish!
SELECT p.projectid, e.eprice, pe.equantity, f.fishid FROM project p
INNER JOIN project_equipment pe ON pe.projectid=p.projectid
INNER JOIN equipment e ON e.equipid=pe.equipid
INNER JOIN project_fish pf ON pf.projectid=p.projectid
ProjectID EPrice EQuantity FishID
1 1 1 1 // from a above
1 1 1 2 // from a above
1 1 1 1 // from b above
1 1 1 2 // from b above
2 1 1 1 // from c above
2 1 1 2 // from c above
2 1 1 1 // from d above
2 1 1 2 // from d above
This duplication will continue with every inner join. The amount your price will be off won't always be 2x, it will actually depend on the number of combinations of all your joins.
So, you can't really do what you are trying to do with this particular query. Instead you'll have to calculate the cost of each relationship separately. Then you sum all those together. You can do this by selecting each one separately and calculating the cost into a ProjectID and ProjectCost column, using UNION to concatenate those altogether, then once again grouping the results by ProjectID and summing the individual ProjectCost subtotals.
I explained that poorly, but think of it as subtotaling equipment, fish, and salary costs, then sticking all those subtotals into one table and summing that. E.g.:
SELECT x.projectid, SUM(x.ProjectCost) FROM
(
SELECT p.projectid, SUM(e.eprice * pe.equantity) ProjectCost FROM project p
INNER JOIN project_equipment pe ON pe.projectid=p.projectid
INNER JOIN equipment e ON e.equipid=pe.equipid
GROUP BY p.projectid
UNION
SELECT p.projectid, SUM(f.fprice * pf.fquantity) ProjectCost FROM project p
INNER JOIN project_fish pf ON pf.projectid=p.projectid
INNER JOIN fish f ON f.fishid=pf.fishid
GROUP BY p.projectid
UNION
SELECT p.projectid, SUM(s.salary) ProjectCost FROM project p
INNER JOIN project_staff ps ON ps.staffid=p.projectid
INNER JOIN staff s ON s.staffid=ps.staffid
GROUP BY p.projectid
) x
GROUP BY x.projectid
Each of the subqueries produces a projectid column and a ProjectCost column. Run the subquery (between the parens) by itself to see the results. The outer query then adds the subtotals for the projects.
Sorry, btw, I renamed your EquipPrice and FishPrice columns to EPrice and FPrice when I was testing.
I am planning to create a website similar to IMDB.com. To reduce execution time I am using the following structure. Is it okay for faster working?
Table - 1
Id Movie_name description
1 name one some description
2 name two some description
3 name three some description
Table 2
id actorname
1 name 1
2 name 2
3 name 3
4 name 4
Table 3
id movieid actorid
1 1 1
2 1 2
3 1 3
4 1 9
5 2 6
6 2 5
7 2 8
8 2 1
When I want to list actors in a movie program will retrieve actors ids from table 3 and find respective names from table 2 (using single query). When I want to list the movies of a actor it will retrieve movie ids from table 3 and find respective names from first table. Will it work properly? Any other ideas?
This will give all actors in a specified movie,
SELECT c.ID, c.actorName
FROM table1 a
INNER JOIN table3 b
ON a.ID = b.movieID
INNER JOIN table2 c
ON b.actorid = c.ID
WHERE a.ID = 1
This one will give all movies for a specified actor
SELECT a.*
FROM table1 a
INNER JOIN table3 b
ON a.ID = b.movieID
INNER JOIN table2 c
ON b.actorid = c.ID
WHERE c.ID = 1
SQLFiddle Demo (both queries)
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
UPDATE 1
This is called Relational Division
SELECT a.ID, a.Movie_Name
FROM table1 a
INNER JOIN table3 b
ON a.ID = b.movieID
INNER JOIN table2 c
ON b.actorid = c.ID
WHERE c.ID IN (1, 2, 3)
GROUP BY a.ID, a.Movie_Name
HAVING COUNT(DISTINCT c.ID) = 3
SQL of Relational Division
I suggest that you modify table3 by taking away the id field. Use the movieid and actorid together as your primary key. You might want to add other fields to this table such as name of character and order of appearance as suggested in the comment by Jermaine Xu.
I have the following table schema:
tbl_portfolio
----------
id (auto number)
name
-
tbl_registration
----------------
id(auto number)
name
portfolio_id (FK to tbl_portfolio.id)
-
tbl_fund
---------
id (auto number)
registration_id (FK to tbl_registration.id)
-
tbl_transaction
---------------
id (auto number)
fund_id (FK to tbl_fund.id)
type
shares
price
I need to create a query that in psuedo-code would do the following:
SELECT port.*, SUM ALL transactions for each portfolio,
FROM tbl_portfolio port
INNER JOIN tbl_registration reg ON reg.portfolio_id = port.id
LEFT JOIN tbl_fund fund on fund.registration_id = reg.id
LEFT JOIN tbl_transaction trans ON trans.fund_id = fund.id
Now of course that query won't work...What I am needing essentially is to sum all the Price * Units for each fund, and then sum those together for each registration, and then sum all of that together for each portfolio.
Each portfolio can have multiple registrations, and each registration can have multiple funds, and each fund can have multiple transactions.
The last item that is throwing a stickler in this, there may be 10's or 100's of portfolios to count so I have no idea how to write the query, much less write it in an effective way that is not relying on subqueries that would cause it to have severely poor performance.
Thank you for the help!
Edit:
PinnyM's answer works and queries the data correctly - however I should expand on the full need.
Besides the tbl_transaction there is also a tbl_distri and tbl_div. Both have fund_id as FK to tbl_fund.id . I need to get the SUM's of tbl_distri.amount and tbl_div.units.
So the full psuedo query would be something to the effect of:
SELECT port.*, SUM ALL transactions for each portfolio, SUM(div.units), SUM(distri.amount)
FROM tbl_portfolio port
INNER JOIN tbl_registration reg ON reg.portfolio_id = port.id
LEFT JOIN tbl_fund fund on fund.registration_id = reg.id
LEFT JOIN tbl_transaction trans ON trans.fund_id = fund.id
LEFT JOIN tbl_distri distri on distri.fund_id = fund.id
LEFT JOIN tbl_div div on div.fund_id = fund.id
Have you tried using SUM()?
SELECT port.*, SUM(trans.shares * trans.price) AS transaction_totals
FROM tbl_portfolio port
INNER JOIN tbl_registration reg ON reg.portfolio_id = port.id
LEFT JOIN tbl_fund fund on fund.registration_id = reg.id
LEFT JOIN tbl_transaction trans ON trans.fund_id = fund.id
GROUP BY port.id
Judging from your question, you are looking for a rolled-up SUM
SELECT port.id AS port_id,
reg.id AS reg_id,
fund.id AS fund_id,
SUM ( trans.shares * trans.price) AS net_asset_value
FROM tbl_portfolio port
INNER JOIN tbl_registration reg ON reg.portfolio_id = port.id
LEFT JOIN tbl_fund fund on fund.registration_id = reg.id
LEFT JOIN tbl_transaction trans ON trans.fund_id = fund.id
GROUP BY port.id, reg.id, fund.id WITH ROLLUP
This will give you the sums id by id. You can use other JOIN operations with this as a subquery to fetch the textual names.
This will give results like this:
port_id reg_id fund_id net_asset_value
1 1 1 150.00
1 1 2 100.00
1 1 NULL 250.00 (rollup of previous two lines)
1 2 1 24.00
1 2 4 80.00
1 2 NULL 104.00 (rollup of previous two lines)
1 NULL NULL 354.00 (rollup at portfolio level)
3 1 1 40.00
3 1 2 50.00
3 1 NULL 90.00 (rollup of previous two lines)
3 2 1 14.00
3 2 4 60.00
3 2 NULL 74.00 (rollup of previous two lines)
3 NULL NULL 164.00 (rollup at portfolio level)
NULL NULL NULL 518.00 (grand total)
The NULLs make it into this resultset because that's what WITH ROLLUP does. This resultset only has the IDs in it; presumably the IDs are unique even if the names aren't. Non-unique names for portfolios, funds, etc, will mess up the GROUP BY pretty badly. Hence my earlier comment about retrieving the names.