Trouble Grouping By Name - sql

I'm having trouble grouping by name (CC.Nome) in this query, can you help me out?
Here is my code:
SELECT
Registadas.CodigoVisualizado As Codigo,
CC.Nome as Entidade,
CC.Documento AS Documento,
CC.DataDocumento as DataDocumento,
ISNULL(ROUND((SELECT SUM(CASE
WHEN tbCCEntidades.Natureza = 'R'
THEN tbCCEntidades.TotalMoedaReferencia
ELSE -tbCCEntidades.TotalMoedaReferencia
END)
FROM tbCCEntidades
WHERE CC.IDEntidade = Entidades.ID), 2), 0) AS Saldo,
CC.Natureza As Natureza
FROM
tbCCEntidades AS CC
INNER JOIN
tbEntidades Entidades ON Entidades.ID = CC.IDEntidade
INNER JOIN
tbEntidadesRegistadas Registadas ON Registadas.IDEntidade = Entidades.ID
What happens is that this query gives the rows mixed like this:

The real problem with your query is that you haven't correlated the sub-query properly:
ISNULL(ROUND((
SELECT SUM( CASE
WHEN tbCCEntidades.Natureza = 'R'
THEN tbCCEntidades.TotalMoedaReferencia
ELSE - tbCCEntidades.TotalMoedaReferencia
END)
FROM tbCCEntidades
Where CC.IDEntidade = Entidades.ID ), 2), 0) AS Saldo,
In this FROM clause you didn't give an alias to the table, so in the WHERE clause neither of the sides of the filter is filtering the subquery. Both CC and Entidades are in the outer query, so this subquery isn't being filtered at all: It's getting the SUM of all rows in the entire table, every time.
I can't be sure of the fix just from this broken code. I would guess instead of CC you need to alias the table in the subquery, and use that alias on the left side of the filter.
Since your sub-query just returns a SUM() it doesn't need a GROUP BY at all, and since it's in a subquery, the SUM() would not be improved by adding a GROUP BY to your main query.

you have to put group by right after where conditions
like
select CC.Name,SUM(something) from TableName where SomeCondition group by CC.Name
and yes you have to put everything on select that is not a aggregate function in group by i would suggest you to go ahead with CTE expression.then make a join on other fields you needed from table.

The query works, it returns the data I need, the thing that I don't know is where to put the "Group By" in order to order the result by CC.Nome :/
You only want to sort your result rows? That's not GROUP BY, but ORDER BY:
...
ORDER BY Entidade;

Related

How to convert inline SQL queries to JOINS in SQL SERVER to reduce load time

I need help in optimizing this SQL query.
In the main SELECT statement there are three columns which is dependent on the outer query result. This is why my query is taking a long time to return data. I have tried making left joins but this is not working properly.
Can anyone help me to resolve this issue?
SELECT
DISTINCT ou.OrganizationUserID AS StudentID,
ou.FirstName,
ou.LastName,
(
SELECT
STRING_AGG(
(ug.UG_Name),
','
)
FROM
Groups ug
INNER JOIN ApplicantUserGroup augm ON augm.AUGM_UserGroupID = ug.UG_ID
WHERE
augm.AUGM_OrganizationUserID = ou.OrganizationUserID
AND ug.UG_IsDeleted = 0
AND augm.AUGM_IsDeleted = 0
) AS UserGroups,
order1.OrderNumber AS OrderId -- UAT-2455
,
(
SELECT
STRING_AGG(
(CActe.CustomAttribute),
','
)
FROM
CustomAttributeCte CActe
WHERE
CActe.HierarchyNodeID = dpm.DPM_ID
AND CActe.OrganizationUserID = ps.OrganizationUserID
) AS CustomAttributes -- UAT-2455
,
(
SELECT
STRING_AGG(
(CActe.CustomAttributeID),
','
)
FROM
CustomAttributeCte CActe
WHERE
CActe.HierarchyNodeID = dpm.DPM_ID
AND CActe.OrganizationUserID = ps.OrganizationUserID
) AS CustomAttributeID
FROM
ApplicantData acd WITH (NOLOCK)
INNER JOIN ClientPackage ps WITH (NOLOCK) ON acd.ClientSubscriptionID = ps.ClientSubscriptionID
INNER JOIN [ClientOrder] order1 WITH (NOLOCK) ON order1.OrderID = ps.OrderID
AND order1.IsDeleted = 0
INNER JOIN OUser ou WITH (NOLOCK) ON ou.OrganizationUserID = ps.OrganizationUserID
It looks like this query can be simplified, and the dependent subqueries in your SELECT clause removed, Consider your second and third dependent subqueries. You can refactor them into one nondependent subquery with a LEFT JOIN. Using nondependent subqueries is more efficient because the query planner can run them just once, rather than once for each row.
You want two STRING_AGG() results from the same table. This subquery gives those two outputs for every possible combination of HierarchyNodeID and OrganizationUserID values. STRING_AGG() is an aggregate function like SUM() and so works nicely with GROUP BY.
SELECT HierarchyNodeID, OrganizationUserID,
STRING_AGG((CActe.CustomAttribute), ',') CustomAttributes -- UAT-2455,
STRING_AGG((CActe.CustomAttributeID), ',') CustomAttributeIDs -- UAT-2455
FROM CustomAttributeCte CActe
GROUP BY HierarchyNodeID, OrganizationUserID
You can run this subquery itself to convince yourself it works.
Now, we can LEFT JOIN that into your query. Like this. (For readability I took out the NOLOCKs and used JOIN: it means the same thing as INNER JOIN.)
SELECT DISTINCT
ou.OrganizationUserID AS StudentID,
ou.FirstName,
ou.LastName,
'tempvalue' AS UserGroups, -- shortened for testing
order1.OrderNumber AS OrderId, -- UAT-2455
uat2455.CustomAttributes, -- UAT-2455
uat2455.CustomAttributeIDs -- UAT-2455
FROM ApplicantData acd
JOIN ClientPackage ps
ON acd.ClientSubscriptionID = ps.ClientSubscriptionID
JOIN ClientOrder order1
ON order1.OrderID = ps.OrderID
AND order1.IsDeleted = 0
JOIN OUser ou
ON ou.OrganizationUserID = ps.OrganizationUserID
LEFT JOIN (
SELECT HierarchyNodeID, OrganizationUserID,
STRING_AGG((CActe.CustomAttribute), ',') CustomAttributes -- UAT-2455,
STRING_AGG((CActe.CustomAttributeID), ',') CustomAttributeIDs -- UAT-2455
FROM CustomAttributeCte CActe
GROUP BY HierarchyNodeID, OrganizationUserID
) uat2455
ON uat2455.HierarchyNodeID = dpm.DPM_ID
AND uat2455.OrganizationUserId = ps.OrganizationUserID
See how we collapsed your second and third dependent subqueries to just one, then used it as a virtual table with LEFT JOIN? We transformed the WHERE clauses from the dependent subqueries into an ON clause.
You can test this: run it with TOP(50) and eyeball the results.
When you're happy, the next step is to transform your first dependent subquery the same way.
Pro tip Don't use WITH (NOLOCK), ever, unless a database administration expert tells you to after looking at your specific query. If your query's purpose is a historical report and you don't care whether the most recent transactions in your database are represented exactly right, you can precede your query with this statement. It also allows the query to run while avoiding locks.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Pro tip Be obsessive about formatting your queries for readability. You, your colleagues, and yourself a year from now must be able to read and reason about queries like this.

SQL Count uses info from join

I need to count the amount of times InternalMenuLinkItemNumber appears per sitenumber and per order mode. Then i need to show MenuItemID and i do that with a inner join using item numbers, but when i add this join it skews the QTY result. I've tried using distinct in the COUNT but then all the QTY is 1. Please assist.
Query and result where QTY result is 100% correct but no MenuItemID.
SELECT ST_Sites.BusinessUnit,[ST_SalesMixTransactions_RealTimeFeed].SiteNumber,InternalMenuLinkItemNumber,[ST_SalesMix].MenuItemID,OrderMode,SellingPrice,COUNT(ST_SalesMixTransactions_RealTimeFeed.InternalMenuLinkItemNumber) as QTY
FROM ST_AlohaSalesMixTransactions_RealTimeFeed
inner join ST_Sites on ST_Sites.SiteNumber= [ST_SalesMixTransactions_RealTimeFeed].SiteNumber
where [ST_SalesMixTransactions_RealTimeFeed].BusinessDate between'2017-06-27'and'2017-07-03' and [ST_SalesMixTransactions_RealTimeFeed].SiteNumber = '1001006'
group by InternalMenuLinkItemNumber,[ST_SalesMixTransactions_RealTimeFeed].SiteNumber,OrderMode,SellingPrice,ST_Sites.BusinessUnit,[ST_SalesMix].MenuItemID
order by InternalMenuLinkItemNumber
Result where QTY comes out as expected:
If I add the inner join to get MenuItemID:
Query:
SELECT ST_Sites.BusinessUnit,[ST_SalesMixTransactions_RealTimeFeed].SiteNumber,InternalMenuLinkItemNumber,[ST_SalesMix].MenuItemID,OrderMode,SellingPrice,COUNT(ST_SalesMixTransactions_RealTimeFeed.InternalMenuLinkItemNumber) as QTY
FROM ST_AlohaSalesMixTransactions_RealTimeFeed
inner join ST_SalesMix on [ST_AlohaSalesMixTransactions_RealTimeFeed].InternalMenuLinkItemNumber= ST_SalesMix.ItemNumber
inner join ST_Sites on ST_Sites.SiteNumber= [ST_SalesMixTransactions_RealTimeFeed].SiteNumber
where [ST_SalesMixTransactions_RealTimeFeed].BusinessDate between'2017-06-27'and'2017-07-03' and [ST_SalesMixTransactions_RealTimeFeed].SiteNumber = '1001006'
group by InternalMenuLinkItemNumber,[ST_SalesMixTransactions_RealTimeFeed].SiteNumber,OrderMode,SellingPrice,ST_Sites.BusinessUnit,[ST_SalesMix].MenuItemID
order by InternalMenuLinkItemNumber
Result where QTY is now way off:
If I use distinct:
Query:
SELECT ST_Sites.BusinessUnit,[ST_SalesMixTransactions_RealTimeFeed].SiteNumber,InternalMenuLinkItemNumber,[ST_SalesMix].MenuItemID,OrderMode,SellingPrice,COUNT(distinct ST_SalesMixTransactions_RealTimeFeed.InternalMenuLinkItemNumber) as QTY
FROM ST_AlohaSalesMixTransactions_RealTimeFeed
inner join ST_SalesMix on [ST_AlohaSalesMixTransactions_RealTimeFeed].InternalMenuLinkItemNumber= ST_SalesMix.ItemNumber
inner join ST_Sites on ST_Sites.SiteNumber= [ST_SalesMixTransactions_RealTimeFeed].SiteNumber
where [ST_SalesMixTransactions_RealTimeFeed].BusinessDate between'2017-06-27'and'2017-07-03' and [ST_SalesMixTransactions_RealTimeFeed].SiteNumber = '1001006'
group by InternalMenuLinkItemNumber,[ST_SalesMixTransactions_RealTimeFeed].SiteNumber,OrderMode,SellingPrice,ST_Sites.BusinessUnit,[ST_SalesMix].MenuItemID
order by InternalMenuLinkItemNumber
Result for QTY is now all 1:
If I understand correctly, you want something like
SELECT SiteNumber, OrderMode, count([DISTINCT?] InternalMenuLinkItemNumber)
...
GROUP BY SiteNumber, OrderMode
You want to count the InternalMenuLinkItemNumber, so InternalMenuLinkItemNumber must not occur in the GROUP BY clause.
EDIT:
When using GROUP BY, the SELECT list may only contain columns also mentioned in the GROUP BY clause, or aggregate functions (on arbitrary columns).
Try this:
SELECT a.InternalMenuLinkItemNumber, a.SiteNumber, a.OrderMode, a.SellingPrice, a.BusinessUnit, a.MenuItemID, a.QTY, CASE WHEN MAX(b.MenuItemID) = MIN(b.MenuItemID) THEN MAX(b.MenuItemID) ELSE -1 END AS MenuItemID
FROM
(SELECT ST_Sites.BusinessUnit, [ST_SalesMixTransactions_RealTimeFeed].SiteNumber, InternalMenuLinkItemNumber, [ST_SalesMix].MenuItemID, OrderMode, SellingPrice, COUNT(ST_SalesMixTransactions_RealTimeFeed.InternalMenuLinkItemNumber) as QTY
FROM ST_AlohaSalesMixTransactions_RealTimeFeed
INNER JOIN ST_Sites on ST_Sites.SiteNumber = [ST_SalesMixTransactions_RealTimeFeed].SiteNumber
WHERE [ST_SalesMixTransactions_RealTimeFeed].BusinessDate between'2017-06-27'and'2017-07-03' and [ST_SalesMixTransactions_RealTimeFeed].SiteNumber = '1001006'
GROUP BY InternalMenuLinkItemNumber, [ST_SalesMixTransactions_RealTimeFeed].SiteNumber, OrderMode, SellingPrice, ST_Sites.BusinessUnit, [ST_SalesMix].MenuItemID
) a
INNER JOIN ST_SalesMix b ON a.InternalMenuLinkItemNumber = b.ItemNumber
GROUP BY a.InternalMenuLinkItemNumber, a.SiteNumber, a.OrderMode, a.SellingPrice, a.BusinessUnit, a.MenuItemID, a.QTY
ORDER BY a.InternalMenuLinkItemNumber
It works on the theory that your first query gives good counts, so keep that as it is (it's now the inner query) and then do the problematic join outside of it. Obviously there are many rows from ST_SalesMix for each properly counted row in the first query, so I'm grouping on the original group list but that means that you might get multiple MenuItemIDs. I'm checking for that in the CASE statement by testing the MAX and MIN MenuItemIDs - if they are the same return MAX(MenuItemID) otherwise I'm returning -1 as an error flag to indicate that there were multiple MenuItemIDs associated with this group. It might not be the most efficient method but I didn't have much to go on.
I hope this helps.
all is sorted now. Thanks to everyone.
#jwolf your suggested query was the answer.

SQL query returning same row of data twice

This query returns the same row of data twice. Is there something wrong with my inner join? Or where clause?
SELECT
transaction_details.transaction_number,
transaction_details.transaction_id,
transaction_details.product_id,
Products3.ProductName
FROM
transaction_details
INNER JOIN
Products3 ON transaction_details.product_id = Products3.productID
INNER JOIN
transaction_status ON transaction_details.transaction_id = transaction_status.transaction_id
WHERE
transaction_details.transaction_id = 'tr-y9404'
AND status_of_transaction = 'pending'
Here is the output
You might have multiple entries in your table? In that case you can use SELECT DISTINCT. This will remove duplicates.

Run WHERE over an Average aggregation result - postgresql

I have the following query that gets the papers grade listing.
SELECT DISTINCT papers.paper_id, papers.paper_title, AVG(paper_judge_participations.paper_judge_participation_score) AS final_grade,
(SELECT array_agg(paper_author_name) FROM paper_authors as authors WHERE authors.paper_id=papers.paper_id )::varchar as paper_author_name
FROM papers
FULL JOIN paper_categories ON paper_categories.paper_category_id=papers.paper_category_id
LEFT JOIN paper_judge_participations ON papers.paper_id = paper_judge_participations.paper_id
WHERE ((papers.paper_note IS NULL AND final_grade >= 7) OR (papers.paper_note IS NOT NULL AND papers.paper_note >= 7)) AND papers.paper_category_id = 1
GROUP BY papers.paper_id ORDER BY final_grade, papers.paper_note;
I want to see if the final_grade variable from the the averae result is more than 7 but I get the error:
ERROR: column "final_grade" does not exist
LINE 6: WHERE ((papers.paper_note IS NULL AND final_grade >= 7) OR (...
How can I use the average result on my WHERE condition?
The distinct is unnecessary in the SELECT. Also you need to move the logic to the HAVING clause:
SELECT p.paper_id, p.paper_title,
AVG(pjp.paper_judge_participation_score) AS final_grade,
(SELECT string_agg(paper_author_name)
FROM paper_authors pa
WHERE pa.paper_id = p.paper_id
) as paper_author_name
FROM papers p LEFT JOIN
paper_categories pc
ON pc.paper_category_id = p.paper_category_id LEFT JOIN
paper_judge_participations pjp
ON p.paper_id = pjp.paper_id
HAVING p.paper_category_id = 1
GROUP BY p.paper_id
HAVING (p.paper_note IS NULL AND final_grade >= 7) OR
(p.paper_note IS NOT NULL AND p.paper_note >= 7) AND
ORDER BY final_grade, p.paper_note;
Comments:
The FULL OUTER JOIN is being turned into a LEFT OUTER JOIN by the WHERE clause. So, you might as well be explicit.
Instead of doing array_agg() and converting the results to a string, how about just using string_agg()?
Table aliases make the query easier to write and read.
And of course, the conditions on the final grade have been moved to the HAVING clause. The condition on the group stays in the WHERE.
Personally, I find it strange that you are using a correlated subquery for one aggregation and explicit aggregation for the other. I suppose that is a matter of preference. Under the circumstance, you might consider using a correlated subquery for both.

Select Case value not sorting correctly in order by

I have a result set that has a defined grouping (for a report). There is a possibility that the position is not assigned and therefore does not have a "Grid_Group". In this case I assign a value of 99. This is working correctly except the order by, the 99 is always first and it should be last (If I do desc it is at bottom). I've tried a cast on the select side as well as within the order by on the Grid_Group, but both have same results with 99 at the top. (Sql server 2008)
Here is the snippet, I remove all other unneeded columns.
SELECT s.SessionNumber,Position.PositionName,(Select CASE when dbo.Position.Grid_Group is null THEN 99 ELSE dbo.Position.Grid_Group END) as Grid_Group
FROM dbo.USession AS us Left Outer JOIN
dbo.Position ON us.PositionId = dbo.Position.PositionId FULL OUTER JOIN
dbo.Sessions AS s ON us.SessionId = s.SessionId
ORDER BY S.SessionNumber, dbo.Position.Grid_Group
Thoughts?
You need to apply the CASE on your order by as well (bear in mind this will ruin index utilization on the sort operation). Your ORDER BY is referencing the original table's column, not your alias result column. Something like this should do the trick:
SELECT
s.SessionNumber,Position.PositionName,
(CASE
WHEN dbo.Position.Grid_Group IS NULL THEN 99
ELSE dbo.Position.Grid_Group
END) AS Grid_Group
FROM dbo.USession AS us
LEFT OUTER JOIN dbo.Position ON us.PositionId = dbo.Position.PositionId
FULL OUTER JOIN dbo.Sessions AS s ON us.SessionId = s.SessionId
ORDER BY
S.SessionNumber,
(CASE
WHEN dbo.Position.Grid_Group IS NULL THEN 99
ELSE dbo.Position.Grid_Group
END)
I allowed myself to apply some minor formatting of your SQL.
An ORDER BY will in this case not see your calculated columns. To get the effect you're asking for, you'll have to ORDER BY the same expression (which kastermester's answer is demonstrating), or wrap the query in a common table expression and ORDER BY while selecting from that, something like;
WITH cte AS (
SELECT s.SessionNumber, p.PositionName, COALESCE(p.Grid_Group, 99) Grid_Group
FROM dbo.USession AS us
LEFT OUTER JOIN dbo.Position p ON us.PositionId = p.PositionId
FULL OUTER JOIN dbo.Sessions s ON us.SessionId = s.SessionId
)
SELECT * FROM cte ORDER BY SessionNumber, Grid_Group;