I am using LEFT JOIN three times in a query to display user information. For some reason, the second last LEFT JOIN affects the output of the SUM function.
I have tried removing the second last LEFT JOIN statement which returns the correct value. I don't see why it would change the value.
SELECT
[tbl_users].[id],
[username],
COUNT([tbl_password_resets].[id]) as passwordresets,
SUM(CASE WHEN [tbl_files].[user_id] = [tbl_users].[id] THEN 1 ELSE 0 END) as uploads,
COUNT([tbl_downloads].[id]) as downloads,
CAST(SUM(CASE WHEN [tbl_downloads].[liked] = 1 OR [tbl_downloads].[disliked] = 1 THEN 1 ELSE 0 END) AS FLOAT) / NULLIF(COUNT([tbl_downloads].[id]), 0) as ratio,
[ban]
FROM
[tbl_users]
LEFT JOIN
[tbl_password_resets] ON [tbl_users].[id] = [tbl_password_resets].[user_id]
LEFT JOIN
[tbl_downloads] ON [tbl_users].[id] = [tbl_downloads].[user_id]
LEFT JOIN
[tbl_files] ON [tbl_files].[user_id] = [tbl_users].[id]
GROUP BY
[tbl_users].[id], [tbl_users].[username], [tbl_users].[ban]
The result for uploads is 9 instead of 3.
If any joined table is duplicating rows, that affects the result of COUNTs and SUMs. Comment out the aggregates and the GROUP BY and the JOINs for testing and see what happens with the row count when you build the query adding the JOINs one-by-one. The more rows fall into one group, the more values will be COUNTed and SUMmed.
Related
I am trying to write a query that returns a count of TotalPlayers in each team who scored less than 10 runs as [LowScoringPlayers], if all the players in a team scored more than 10 runs, I still need to print the TeamName and 0 as the [LowScoringPlayers] for that team.
My below query gives me the count correctly but if there are no players in a team who scored less than 10 runs then it skips printing that TeamName.
SELECT DISTCINT
(TM.[TeamId]), TM.[TeamName],
COUNT(DISTINCT S.[PlayerId]) AS [LowScoringPlayers]
FROM
dbo.[Teams] TM
INNER JOIN
dbo.[Player] PL ON PL.[PlayerId] = TM.[TeamId]
INNER JOIN
dbo.[ScoreAudit] S ON S.[PlayerId] = PL.[PlayerId] AND S.[Runs] <= 10
GROUP BY
TM.[TeamId], TM.[TeamName]
If I remove the condition S.[Runs] <=10 the query prints all the team names.. 1 way I could think of is using a case statement before S.[Runs] <=10, but the data is huge so there might be performance issues.
Any other better way?
Use LEFT JOIN in your query. So, solution can be:
SELECT DISTINCT TM.TeamId, TM.TeamName, COUNT(DISTINCT S.PlayerId) AS LowScoringPlayers
FROM dbo.Teams TM
LEFT JOIN dbo.Player PL
ON PL.PlayerId = TM.TeamId
LEFT JOIN dbo.ScoreAudit S
ON S.PlayerId = PL.PlayerId AND S.Runs <=10
GROUP BY TM.TeamId, TM.TeamName
I need your help to understand below query can anyone help me to describe it, i wanted to know the role of b.id is null and r.id is null in below query if anyone can explain whole code then it would be great?
select l.id as start,
(
select min(a.id) as id
from sequence as a
left outer join sequence as b on a.id = b.id - 1
where b.id is null
and a.id >= l.id
) as end
from sequence as l
left outer join sequence as r on r.id = l.id - 1
where r.id is null;
This query returns your "islands"of your sequence, i.e. start and end of continuos id intervals.
You can read more on gaps and islands here: Special Islands and here The SQL of Gaps and Islands in Sequences
The query is finding islands of consecutive numbers, outputting the start and end of ranges where all consecutive numbers are there, so for the set if numbers
{1,3,4,5,6,9,10}
I would expect
1,1
2,6
9,10
to be selected
The outer query starts by finding number (N) that cannot join to a record holding N-1, detected by r.id is null
The sub query then finds the next highest number (M) that does not join to a record holding M+1 (detected using b.id is null)
so in my example 3 does not have a '2' to join to, meaning 3 begins a range. The first number >= to that with no subsequent record is 6, which has no '7' to make a join to
The query is joining two tables (in this case the same table but it does not matter) using an outer join.
if we have
SELECT t1.a, t1.b, t2.d
FROM table1 t1
LEFT OUTER JOIN table2 t2 ON t1.a = t2.a
WHERE t2.a is null
This means it returns a set of records with all those from table1, however its possible there will not be a joined record from table2 for every record in table1. If there isn't the table2 fields are returned as null so the the WHERE clause is effectively saying return me all records from table1 where we do not have a join record in table2.
In your example where it joins onto itself you are looking where there is not a next/previous record (depending upon which way you are looking at it) based upon the id e.g. if id = 5, then there is not a record with id = 4
Overall the sql as a whole looks like its returning the consecutive id ranges in the sequence table.
I am new to writing MS SQL queries and I am trying to display only the record with the highest field named RecordVersion.
Below is the query that works but displays all records:
SELECT
PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
Here are the query results:
PriceProgramID EffectiveDateTime Price PLU Descr LastUpdate LastUpdatedBy RecordVersion PriceScheduleUniqueID
1 2016-03-22 00:00:00.000 35.00 SLS10100103 Architecture Adult from NP POS 2015-01-22 07:53:15.000 GX70,83 9 569
1 2016-03-22 00:00:00.000 32.00 SLS10100103 Architecture Adult from NP POS 2014-02-25 16:22:46.000 GX70,83 5 86180
The first line of the results has RecordVersion being 9 and the second line results is 5, I only want the higher record displaying, the one that returned RecordVersion = 9.
Every time I try to use the MAX command I get errors or the group by and I have tried every example I could find on the web but nothing seems to work.
Using MS SQL 2012.
Thanks,
Ken
Try the following query which attempts to solve your problem by ordering the returned rows by RecordVersion DESC and then SELECTs just the first row.
SELECT TOP 1
PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
ORDER BY
RecordVersion DESC
All group by columns should be in select ,that's the rule of group by.How group by works is for every distinct combination of group by columns,arrange remaining columns into groups,so that any aggregation can be applied,in your case I am not sure what group by columns are unique with out test date.here is one version which use row number which gives you the output desired
Remember ,order by last updated date is the one which decides rows order and assign numbers
WITH CTE
AS
(
SELECT PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID,
ROW_NUMBER() OVER (PARTITION BY PriceSchedules.RecordVersion ORDER BY PriceSchedules.LastUpdatedBy) AS RN
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
)
SELECT * FROM CTE WHERE RN=1
I do a SELECT with a CASE statement with this following:
SELECT DISTINCT
n.NiveauId, n.Description,
CASE WHEN n.NiveauId NOT IN (SELECT ccs.idNiveau WHERE ccs.centreCout = 60001) THEN 0 ELSE 1 END AS attribue
FROM pa.dbo.Niveau n
JOIN BDC.dbo.CentreCoutSecteur ccs ON n.NiveauId = ccs.idNiveau
Explication :
In case "NiveauId" is not present in the other table, the value of "attribue" is 0. Else, if it's present, the value is 1.
This works, but every rows that contains a 1 also shows the same row with a 0.
Exemple:
How would I change the SELECT query to remove the unwanted duplicate rows that contain 0?
Thanks in advance!
Try wrapping your select in a max (if you only want the rows with the highest value for attribue.
SELECT b.NiveauID, b.Description, MAX(b.attribue)
FROM
(SELECT DISTINCT
n.NiveauId, n.Description,
CASE WHEN n.NiveauId NOT IN (SELECT ccs.idNiveau WHERE ccs.centreCout = 60001) THEN 0 ELSE 1 END AS attribue
FROM pa.dbo.Niveau n
JOIN BDC.dbo.CentreCoutSecteur ccs ON n.NiveauId = ccs.idNiveau) b
Group By b.NiveauID, b.Description
I'm using a SQL question were I want to find the lowest value from the field prod_week.
This is the query:
SELECT
MIN(oe.prod_week), oe.prodplan_id
FROM
pd_mounting_details as md
LEFT OUTER JOIN
pd_order_eco AS oe ON md.order_data = oe.id
LEFT OUTER JOIN
pd_article AS a ON md.article = a.id
WHERE
oe.status = 4
AND (md.starttime = '' OR md.starttime IS NULL)
AND (a.production_group = 4)
AND (NOT (oe.amount = 0))
GROUP BY
oe.prodplan_id
The result of this is
prod_week | prodplan_id
1126 | 27
1127 | 28
What I don't understand is why this result in two rows when I used MIN(prod_week) to get the row with the lowest week number.
If I remove the prodplan_id from the selection it all works and I get one row were prod_week is "1126". And from that all I want is to get the id prodplan_id to.
I hope this question isn't to blurry?
You are using GROUP BY, which means you will get one row per GROUP.
In this case your GROUP is prodplan_id and there are two matching values.
To get both values you can try:
SELECT oe.prod_week, oe.prodplan_id
FROM pd_mounting_details as md
LEFT OUTER JOIN pd_order_eco AS oe
ON md.order_data = oe.id
WHERE oe.prod_week = (SELECT MIN(oe.prod_week)
FROM pd_mounting_details as md
LEFT OUTER JOIN pd_order_eco AS oe
ON md.order_data = oe.id
LEFT OUTER JOIN pd_article AS a
ON md.article = a.id where oe.status=4
AND (md.starttime ='' or md.starttime is null)
AND (a.production_group = 4)
AND (NOT (oe.amount = 0)))
When you do
select min(x),y
from table
group by y;
what you're doing is getting y and the smallest value of x for each distinct value of y. So, since prodplan_id has values of 27 and 28 in your morass of joins, we have that the smallest value of prod_week that appears when prodplan_id=27 is 1126, and the smallest value of prod_week that appears when prodplan_id=28 is 1127.
ETA: If you want one row, you could do an order by 1 limit 1 at the end.
ETA^2: You can also wrap things up in a subquery and use a where clause at the end:
select min_prod_week,prodplan_id
from(
select min(oe.prod_week) as min_prod_week,oe.prodplan_id
from....
group by oe.prodplan_id
)min
where min_prod_week=(select min(prod_week) from pd_order_eco)
Since your select statement ends with a group by clause, you are selecting the minimum prod_week for each prodplan_id instead of the overall minimum. Remove the group by clause and it should work as you expect.