SQL Server : Combining Query Results - sql-server

I have a program that stores different types "Assets" for buildings which can be marked as being "Removed". I can create a query to count the number of assets by type and another to count the number of items identified as still present. But what I want to do is combine the two into 1 table.
Query 1
SELECT
theAssetOutletType, COUNT(id) AS TotalNoOfAssets
FROM
dbo.tblLEGAssets
WHERE
buildingID = 1
GROUP BY
theAssetOutletType
Query 2
SELECT
theAssetOutletType, COUNT(id) AS ItemsStillPresent
FROM
dbo.tblLEGAssets
WHERE
buildingID = 1 AND removed <> 0
GROUP BY
theAssetOutletType
Thank you in advance for any help

I would suggest conditional aggregation:
SELECT theAssetOutletType,
COUNT(*) as TotalNoOfAssets
SUM(CASE WHEN removed <> 0 THEN 1 ELSE 0 END) as ItemsStillPresent
FROM dbo.tblLEGAssets
WHERE buildingID = 1
GROUP BY theAssetOutletType;
This puts the values in separate columns on the same row -- which makes more sense to me than on separate rows.

Try Union:
SELECT theAssetOutletType, count(id) as TotalNoOfAssets FROM dbo.tblLEGAssets where buildingID=1 group by theAssetOutletType
UNION
SELECT theAssetOutletType, count(id) as ItemsStillPresent FROM dbo.tblLEGAssets where buildingID=1 and removed<> 0 group by theAssetOutletType

I've found a work around, by using a nested select - that I can use, but if it is still possible I'd love to know the answer:
SELECT theassetoutlettype,
noofitems,
noremoved,
noofitems - noremoved AS noLeft
FROM (SELECT theassetoutlettype,
Count(id) AS NoOfItems,
Sum(removed) AS noRemoved
FROM dbo.tbllegassets
WHERE buildingid = 1
GROUP BY theassetoutlettype) nested

I finally found a solution... took a lot of trial and error but it now works. Here is my Stored Procedure Solution, with the additional table "tblLEGAssetOutletTypes" which contains a single fields with a list of the 6 asset types. The following code will always return 6 rows with the project type, the total number of assets, the number of assets removed and the total remaining. Hope someone else who needs a similar problem resolving an use the code:
SELECT tblLEGAssetOutletTypes.assetOutletType, nested.NoOfItems, nested.noRemoved, NoOfItems-noRemoved AS noLeft
FROM (SELECT theAssetOutletType, COUNT(id) AS NoOfItems, SUM(removed) AS noRemoved
FROM tblLEGAssets
where buildingID=#buildingID
GROUP BY theAssetOutletType) AS nested
RIGHT JOIN tblLEGAssetOutletTypes ON nested.theAssetOutletType = tblLEGAssetOutletTypes.assetOutletType;

Related

Querying in SQL-

I have a table named "Results" like below:
I'd like to count personnel who have been completely scored. It means the ones who have no zero in score column. For example based on the uploaded picture just person with ID 1004 should be counted and the outcome should be one.
I used this code:
select Count(PrsID) from results
where Score <> 0
group by PrsID
But it wouldn't help me cause if a person has just one non-zero score, he will be counted!
Thanks in advance.
If I understand you correctly, I think this is what you want: SELECT COUNT(DISTINCT(PrsID)) FROM results WHERE PrsID NOT IN (SELECT DISTINCT PrsID FROM results WHERE score = 0)
If a person's min score is greater than zero, then they should be counted.
select count(1)
from (
select PrsID
from results
group by PrsID
having min(Score) > 0) as results
You can use conditional aggregation as below:
Select PrsId from results
group by PrsId
having sum(case when score = 0 then 1 else 0 end) > 1
I think you want something like:
select PrsID, Count(1) from results
where Score = 0
group by PrsID
This one returns count of person who has non zero score
SELECT
t1.PrsID,
Count(t1.PrsID)
FROM
( SELECT
*
FROM results
GROUP BY results.PrsID
ORDER BY results.Score ASC
) AS t1
WHERE t1.Score <> 0;

select statement with "Group by" on specific columns but displaying other columns along with group by columns

I want to get all data based on group by of only encounter,medicationname
column data..
select encounter,medicationname,count(*) as freq,labdate,result
from Medications where (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
group by encounter,medicationname having count(*)>2
I have records like
encounter medicationname freq
8604261 ACC 3
Now based on this data ,I want to get
This is my desired output
encounter medicationname labtime result
8604261 ACC 2015-05-22 18
8604261 ACC 2015-07-23 23
8604261 ACC 2015-09-09 27
You can use COUNT() as a window function, something like this:
;With Counted as (
SELECT encounter,medicationname,labdate,result,
COUNT(*) OVER (PARTITION BY encounter,medicationname) as cnt
from Medications
where (labdate between #admitdate
and DATEDIFF(dd,24,#admitdate))
)
select encounter,medicationname,labdate,result
from Counted
where cnt > 2
I would note that I think DATEDIFF1 is probably wrong also but since I don't have your data, inputs and an actual spec, I've left it as is for now.
1DATEDIFF returns an int, but you're using it in a comparison against a column which is apparently a date. DATEADD would be the more probably desired function here, but as I say, I don't have full information to go on.
If I understand you question correctly what you need is this
;WITH CTE AS
(
select encounter,medicationname,count(*) as freq,labdate,result
from Medications where (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
group by encounter,medicationname having count(*) > 2
)
select encounter,medicationname,labdate,result
from Medications M
INNER JOIN CTE C
ON M.encounter = C.encounter
AND M.medicationname = C.medicationname
where (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
or better yet using COUNT()OVER()
;WITH CTE AS
(
SELECT encounter,medicationname,COUNT(*) OVER(PARTITION BY encounter,medicationname)as freq,labdate,result
FROM Medications
WHERE (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
)
SELECT * FROM CTE
WHERE freq > 2
select encounter,medicationname,count(*) as freq,labdate,result
from Medications
where (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
group by encounter,medicationname having count(*) > 2

Subquery in a Stored Procedure

My problem is that out of two tables I need a result set presenting the number of ordered items per PLU and the number of items still on stock.
I cannot do it in ONE stored procedure.
My query presenting the orders.
SELECT
tblOrderDetails.PLU, tblArtikel.Description,
SUM(tblOrderDetails.Pieces) AS Pieces
FROM
tblOrderDetails
INNER JOIN
tblArtikel ON tblOrderDetails.PLU = tblArtikel.PLU
GROUP BY
tblOrderDetails.PLU, tblArtikel.Description
returns as output:
30002 BA4875 3
30012 UK8798 15
My stock is queried with
(SELECT SUM(tblStock.Pieces) AS Ls, tblStock.PLU
from tblStock
GROUP BY tblStock.PLU)
The result should look like:
30002 BA4875 3 0
30012 UK8798 15 8
meaning that for artikelno 30002 there are 3 ordered and 0 on stock
So, how can I combine both queries (resultsets) in one SP?
I always get error
Msg 116
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
I know what the error is, but without the PLU in the stock-query I do not know how to combine both resultsets.
Thanks yr. help
Michael
Can you please try the below
SELECT
tblOrderDetails.PLU, tblArtikel.Description,
SUM(tblOrderDetails.Pieces) AS Pieces
FROM tblOrderDetails
INNER JOIN tblArtikel ON tblOrderDetails.PLU = tblArtikel.PLU
where exists
(
select SUM(tblStock.Pieces) AS Ls, tblStock.PLU from tblStock
where tblArtikel.PLU = tblStock.PLU
GROUP BY tblStock.PLU
having SUM(tblStock.Pieces) > 0
)
GROUP BY tblOrderDetails.PLU, tblArtikel.Description
Please let me know if this helps

SQL Server reference fields in derived table with unions

I'm having a bit of an issue with some derived tables that I hope someone will be able to help with. What I've got is 2 derived tables inside a select statement that then uses a pivot to display the results horizontally rather than vertically.
What I've got so far is:
SELECT * FROM(
SELECT SUM(Value) AS TotDays, ClassId FROM MainTable GROUP BY ClassId)
Union All
SELECT SUM(NumDays) As TotDays, ClassId FROM (
SELECT CASE WHEN COUNT(SiteId) > 0 THEN 1 ELSE 0 END AS NumDays
FROM Table2 GROUP BY ClassId ) as SUB
) AS a
PIVOT (SUM(TotDays) FROM ClassId
IN ([12],[13],[14],[15]
What I'm trying to do is reference the individual columns rather than using SELECT *, but I don't know how to do it. I can make it work without if I drop everything from the union onwards, but when I put the union in it doesn't work and I have to use SELECT *.
Anyone got any ideas on what's going wrong?
Thanks
Alex
You have a couple of errors on your query. For example, your UNION ALL has sets with a different number of columns, and you have other syntax errors. Try this way:
SELECT [12],[13],[14],[15]
FROM ( SELECT SUM(Value) AS TotDays, ClassId
FROM MainTable
GROUP BY ClassId
UNION ALL
SELECT SUM(NumDays) As TotDays, ClassId
FROM ( SELECT CASE WHEN COUNT(SiteId) > 0 THEN 1 ELSE 0 END NumDays,
ClassId
FROM Table2
GROUP BY ClassId) as SUB
) AS a
PIVOT (SUM(TotDays) FROM ClassId IN ([12],[13],[14],[15])) AS PT

Anyway to get a value similar to ##ROWCOUNT when TOP is used?

If I have a SQL statement such as:
SELECT TOP 5
*
FROM Person
WHERE Name LIKE 'Sm%'
ORDER BY ID DESC
PRINT ##ROWCOUNT
-- shows '5'
Is there anyway to get a value like ##ROWCOUNT that is the actual count of all of the rows that match the query without re-issuing the query again sans the TOP 5?
The actual problem is a much more complex and intensive query that performs beautifully since we can use TOP n or SET ROWCOUNT n but then we cannot get a total count which is required to display paging information in the UI correctly. Presently we have to re-issue the query with a #Count = COUNT(ID) instead of *.
Whilst this doesn't exactly meet your requirement (in that the total count isn't returned as a variable), it can be done in a single statement:
;WITH rowCTE
AS
(
SELECT *
,ROW_NUMBER() OVER (ORDER BY ID DESC) AS rn1
,ROW_NUMBER() OVER (ORDER BY ID ASC) AS rn2
FROM Person
WHERE Name LIKE 'Sm%'
)
SELECT *
,(rn1 + rn2) - 1 as totalCount
FROM rowCTE
WHERE rn1 <=5
The totalCount column will have the total number of rows matching the where filter.
It would be interesting to see how this stacks up performance-wise against two queries on a decent-sized data-set.
you'll have to run another COUNT() query:
SELECT TOP 5
*
FROM Person
WHERE Name LIKE 'Sm%'
ORDER BY ID DESC
DECLARE #r int
SELECT
#r=COUNT(*)
FROM Person
WHERE Name LIKE 'Sm%'
select #r
Something like this may do it:
SELECT TOP 5
*
FROM Person
cross join (select count(*) HowMany
from Person
WHERE Name LIKE 'Sm%') tot
WHERE Name LIKE 'Sm%'
ORDER BY ID DESC
The subquery returns one row with one column containing the full count; the cross join includes it with all rows returned by the "main" query"; and "SELECT *" would include new column HowMany.
Depending on your needs, the next step might be to filter out that column from your return set. One way would be to load the data from the query into a temp table, and then return just the desired columns, and get rowcount from the HowMany column from any row.

Resources