Where clause in GROUP BY clause containing ranges - sql-server

I want a mechanism where the the number of reported cases for the age ranges will be for a particular date. But the WHERE clause BioData.[Date] = '05/16/2016' is giving an error.
Can someone please help me to fix it.
My query is as following:
SELECT t.[Range] AS [Age Range], COUNT(*) AS [Number of Reported Cases]
FROM (
SELECT
CASE
WHEN Age BETWEEN 0 AND 6 THEN ' 0-6 '
WHEN Age BETWEEN 07 AND 17 THEN '10-19'
WHEN Age BETWEEN 18 AND 60 THEN '20-29'
ELSE '60+'
END AS [Range]
FROM BioData
) t
WHERE BioData.[Date] = '05/16/2016'
GROUP BY t.[Range]

Try reformating your query with a tool like http://www.dpriver.com/pp/sqlformat.htm
SELECT t.range AS [Age Range],
Count(*) AS [Number of Reported Cases]
FROM (SELECT CASE
WHEN age BETWEEN 0 AND 6 THEN ' 0-6 '
WHEN age BETWEEN 07 AND 17 THEN '10-19'
WHEN age BETWEEN 18 AND 60 THEN '20-29'
ELSE '60+'
END AS range
FROM biodata) t
WHERE biodata.[Date] = '05/16/2016'
GROUP BY t.range
You realize [biodata] doesnt exist because your FROM is just [t]
You probably are missing the JOIN biodata but because your question isnt clear I cant guess what else you need.
EDIT: After some digging I think you want this
SELECT t.range AS [Age Range],
Count(*) AS [Number of Reported Cases]
FROM (SELECT CASE
WHEN age BETWEEN 0 AND 6 THEN ' 0-6 '
WHEN age BETWEEN 07 AND 17 THEN '10-19'
WHEN age BETWEEN 18 AND 60 THEN '20-29'
ELSE '60+'
END AS range
FROM biodata
WHERE biodata.[Date] = '05/16/2016' ) t
-- ^^^ move where inside `t`
GROUP BY t.range

Related

t-sql loop through all rows and sum amount from column until value is reached

I have a table containing the below test data:
I now would like to fill a restaurant with 12 seating spaces.
This should result in:
Basically, I need to loop from top to bottom through all rows and add the AmountPersons until I have filled the restaurant.
In this example:
(first few rows: AmountPersons) 3+1+2+4 = 10
UserId 52 can't be added because they reserved for 3 persons, which would result in 13 occupied places and there are only 12 available.
In the next row it notices a reservation for 1. This can be added to the previous 10 we already found.
NewTotal is now 11.
UserId 79 and 82 can't be added because we'd exceed the capacity again.
UserId 95 reserved for 1, this one can be added and we now have all places filled.
This is the result I get from the cursor I use, but I'm stuck now. Please help.
The while loop I have in the cursor basically stops when the next value would be higher than 12. But that is not correct.
Because you want to skip rows, you need a recursive CTE. But it is tricky -- because you may not have a group following your rules that adds up to exactly 12.
So:
with tn as (
select t.*, row_number() over (order by userid) as seqnum
from t
),
cte as (
select userId, name, amountPersons as total, 1 as is_included, seqnum
from tn
where seqnum = 1
union all
select tn.userId, tn.name,
(case when tn.amountPersons + cte.total <= 12
then tn.amountPersons + cte.total
else cte.total
end),
(case when tn.amountPersons + cte.total <= 12
then 1
else 0
end) as is_included,
tn.seqnum
from cte join
tn
on tn.seqnum = cte.seqnum + 1
where cte.total < 12
)
select cte.*
from cte
where is_included = 1;
Here is a db<>fiddle.
Note that if you change "I" to a larger value, then it is not included and the number of occupied seats is 11, not 12.

T-SQL Pivot Error: Incorrect syntax near '0'

I'm not sure what I'm doing wrong in my code. I get an error message:
Msg 102, Level 15, State 1, Line 82
Incorrect syntax near '0'
Can someone help find what my error is? I'm trying to pivot the table so that the query returns Headers with the age groups instead of the rows.
SELECT *
FROM
(SELECT
ID,
CASE
WHEN Age BETWEEN 0 AND 4 THEN '0-4 Years'
WHEN Age BETWEEN 5 AND 24 THEN '5-24 Years'
WHEN Age BETWEEN 25 AND 49 THEN '25-49 Years'
WHEN Age BETWEEN 50 AND 64 THEN '50-64 Years'
WHEN Age > 64 THEN '> 64 Years'
END AS GroupAge
FROM
#AD) t
PIVOT
(COUNT(ID)
FOR GroupAge IN
(0-4 Years,5-24 Years,25-49 Years,> 64 Years)
) AS pvt
Put square brackets [] around your pivoted column names.
PIVOT
(
COUNT(ID)
FOR GroupAge IN
([0-4 Years],[5-24 Years],[25-49 Years],[50-64 Years],[> 64 Years])
) AS pvt
The error caused you to need to use square brackets in pivot columns, because of the 0-4 Years .. columns isn't normal string.
I would use condition aggregate function do pivot.
SELECT
COUNT(CASE WHEN Age BETWEEN 0 AND 4 THEN ID END) '0-4 Years',
COUNT(CASE WHEN Age BETWEEN 5 AND 24 THEN ID END) '5-24 Years' ,
COUNT(CASE WHEN Age BETWEEN 25 AND 49 THEN ID END) '25-49 Years',
COUNT(CASE WHEN Age BETWEEN 50 AND 64 THEN ID END) '50-64 Years',
COUNT(CASE WHEN Age > 64 THEN ID END) '> 64 Years'
FROM #AD

Accumulative Update for previous records

I have table that shows these information
Month NewClients OnHoldClients
5-2017 10 2
6-2017 16 4
7-2017 11 1
8-2017 15 6
9-2017 18 7
I am trying to find the accumulative total for each month
which is
(NewClients - OnHoldClients) + Previous Month Total
Something like this
Month NewClients OnHoldClients Total
5-2017 10 2 8
6-2017 16 4 20
7-2017 11 1 30
8-2017 15 6 39
9-2017 18 7 50
the query i tried to build was something like this but I think should be an easier way to do that
UPDATE MyTable
SET Total = (SELECT TOP 1 Total FROM MyTable B WHERE B.Month < A.Month) + NewClients - OnHoldClients
FROM MyTable A
Before we begin, note the mere fact that you're facing such calculative problem is a symptom that maybe you don't have the best possible design. Normally for this purpose calculated values are being stored along the way as the records are inserted. So i'd say you'd better have a total field to begin with and calculate it as records amass.
Now let's get down to the problem at hand. i composed a query which does that nicely but it's a bit verbose due to recursive nature of the problem. However, it yields the exact expected result:
DECLARE #dmin AS date = (SELECT min(mt.[Month]) from dbo.MyTable mt);
;WITH cte(_Month, _Total) AS (
SELECT mt.[Month] AS _Month, (mt.NewClients - mt.OnHoldClients) AS _Total
FROM dbo.MyTable mt
WHERE mt.[Month] = #dmin
UNION ALL
SELECT mt.[Month] AS _Month, ((mt.NewClients - mt.OnHoldClients) + ccc._Total) AS _Total
FROM dbo.MyTable mt
CROSS APPLY (SELECT cc._Total FROM (SELECT c._Total,
CAST((row_number() OVER (ORDER BY c._Month DESC)) AS int) as _Rank
FROM cte c WHERE c._Month < mt.[Month]) as cc
WHERE cc._Rank = 1) AS ccc
WHERE mt.[Month] > #dmin
)
SELECT c._Month, max(c._Total) AS Total
FROM cte c
GROUP BY c._Month
It is a recursive CTE structure that goes about each record all along the way to the initial month and adds up to the final Total value. This query only includes Month and Total fields but you can easily add the other 2 to the list of projection.
Try this
;WITH CTE([Month],NewClients,OnHoldClients)
AS
(
SELECT '5-2017',10,2 UNION ALL
SELECT '6-2017',16,4 UNION ALL
SELECT '7-2017',11,1 UNION ALL
SELECT '8-2017',15,6 UNION ALL
SELECT '9-2017',18,7
)
SELECT [Month],
NewClients,
OnHoldClients,
SUM(MonthTotal)OVER( ORDER BY [Month]) AS Total
FROM
(
SELECT [Month],
NewClients,
OnHoldClients,
SUM(NewClients-OnHoldClients)OVER(PArtition by [Month] Order by [Month]) AS MonthTotal
FROM CTE
)dt
Result,Demo:http://rextester.com/DKLG54359
Month NewClients OnHoldClients Total
--------------------------------------------
5-2017 10 2 8
6-2017 16 4 20
7-2017 11 1 30
8-2017 15 6 39
9-2017 18 7 50

Sql comparaison nested on one column

Imagine a table :
ID Month Year Value 1
1 May 17 58
2 June 09 42
3 December 18 58
4 December 18 58
5 September 10 84
6 May 17 42
7 January 16 3
I want to return all the data that shares the same month and year where Value 1 is different. So in our example, I want to return 1 and 6 only but not 3 and 4 or any of the other entries.
Is there a way to do this? I am thinking about a combination of distinct and group by but can't seem to come up with the right answer being new to SQL.
Thanks.
It could be done without grouping, but with simple self-join:
select distinct t1.*
from [Table] t1
inner join [Table] t2 on
t1.Month = t2.Month
and t1.Year = t2.Year
and t1.Value_1 <> t2.Value_1
You can find some information and self-join examples here and here.
For each row you can examine aggregates in its group with the OVER clause. eg:
create table #t(id int, month varchar(20), year int, value int)
insert into #t(id,month,year,value)
values
(1,'May' ,17, 58 ),
(2,'June' ,09, 42 ),
(3,'December' ,18, 58 ),
(4,'December' ,18, 58 ),
(5,'September',10, 84 ),
(6,'May' ,17, 42 ),
(7,'January' ,16, 3 );
with q as
(
select *,
min(value) over (partition by month,year) value_min,
max(value) over (partition by month,year) value_max
from #t
)
select id,month,year,value
from q
where value_min <> value_max;
If I understood your question correctly, you are looking for the HAVING keyword.
If you GROUP BY Month, Year, Value_1 HAVING COUNT(*) = 1, you get all combinations of Month, Year and Value_1 that have no other occurrence.

Join/UNION ALL to show result in different columns

I am fetching COUNT from 3 different table based on some conditions but to group them on time interval. (Like: 1 hour, 30 minutes.)
I need the following output:
Date Interval Success Un-Success Closed CLInotFound
2/20/2016 01:01 – 02:00 5 3 2 13
2/20/2016 02:01 – 03:00 14 9 23 5
2/20/2016 03:01 – 04:00 8 67 89 345
2/20/2016 04:01 – 05:00 2 23 92 12
2/20/2016 05:01 – 06:00 44 55 78 98
2/20/2016 06:01 – 07:00 12 87 56 445
I am able to calculate them separately but when I am trying to combine the result gets different.
Query 1 For Success & Un-Success:
SELECT CONVERT(VARCHAR(5), A.InsertionDate ,108) AS 'Interval',
COUNT(CASE WHEN A.call_result = 0 then 1 ELSE NULL END) AS 'Success',
COUNT(CASE WHEN A.call_result = 1 then 1 ELSE NULL END) AS 'Un-Success'
from dbo.AutoRectifier A
WHERE CONVERT(DateTime,A.InsertionDate,101) BETWEEN '2016-02-19 02:10:35.000' AND '2016-02-19 07:15:35.000'
GROUP BY A.InsertionDate;
Query 2 For Closed:
SELECT CONVERT(VARCHAR(5), C.DateAdded ,108) AS 'Interval',
COUNT(*) AS 'Closed' FROM dbo.ChangeTicketState C
WHERE C.SourceFlag = 'S-CNR' AND C.RET LIKE '%CLOSE%'
AND C.DateAdded BETWEEN '2016-02-19 02:10:35.000' AND '2016-02-19 07:15:35.000'
GROUP BY C.DateAdded;
Query 3 For CLI Not Found:
SELECT CONVERT(VARCHAR(5), T.DateAdded ,108) AS 'Interval',
COUNT(*) 'CLI Not Found' FROM dbo.TICKET_INFO T
WHERE T.CONTACT_NUMBER = '' AND T.DateAdded BETWEEN '2016-02-19 02:10:35.000' AND '2016-02-19 07:15:35.000'
GROUP BY T.DateAdded;
You have got several problems to solve in you question.
You have to produce a union result set from Query1, Query2, Query3 to group it. You can use UNION ALL for it but all 3 queries must have similar column list for it. So, add
0 as Closed, 0 as CLInotFound
to select-list of the Query1,
add
0 as Success, 0 as Un-Success, 0 as CLInotFound
to select-list of the Query2 and add
0 as Success, 0 as Un-Success, 0 as Closed
to Query3
Then you can write
select * from Query1
union all
select * from Query2
union all
select * from Query3
Don't convert date to varchar at Query1, Query2, Query3. Better return datetime from query to use it for grouping after union. So, query 1 will look like
SELECT A.InsertionDate AS Date, ...
Query2 -
SELECT C.DateAdded AS Date, ...
etc.
Then you can group results on per-hour basis, for instance using GROUP BY SUBSTRING(CONVERT(VARCHAR(20), Date ,120), 1, 13)
So, the result will look like
SELECT SUBSTRING(CONVERT(VARCHAR(20), Date ,120), 1, 13) as Interval,
sum(Success) as
sum(Un-Success) as,
sum(Closed) as,
sum(CLInotFound) as
from (
select * from Query1
union all
select * from Query2
union all
select * from Query3
) q
GROUP BY SUBSTRING(CONVERT(VARCHAR(20), Date ,120), 1, 13)
Its result have slightly different format of Date and Interval field, but shows the idea.
You can use GROUP BY DATEPART(yy, Date), DATEPART(mm, Date), DATEPART(dd, Date), DATEPART(hh, Date) instead of GROUP BY SUBSTRING(CONVERT(VARCHAR(20), Date ,120), 1, 13) and format if as you wish.
Also result set does not contain intervals that not present at original data.
You can add Query4, containing all intervals required and zeros at all fields to fix it.

Resources