How to make Query for that - sql-server

I have a table structure from there i have to make a query in some different way
Table Structure
id unique identifier
code varchar(5) Not Null
Recording_date Datetime Not Null
Max_Temp numeric(5,2) Not Null
Min_Temp numeric(5,2) Not Null
We have some data as well in this table.We have data only for 2013 year and for first 3 months.
But the main thing is that i have to return's data in such a format like
Please help me to create a query for such a logic.
Thanks in advance.

Presuming you have one recording per day then
SELECT
DATEPART(m, Month_Start) + ' ' + DATEPART(yyyy, Month_Start)
, Max_Temp_Days
, CASE
WHEN Denominator = 0 THEN 0
ELSE (Max_Temp_Days / Denominator) * 100
END AS Percent_Max_Temp_Days
, Min_Temp_Days
, CASE
WHEN Denominator = 0 THEN 0
ELSE (Min_Temp_Days / Denominator) * 100
END AS Percent_Max_Temp_Days
FROM (
SELECT
DATEADD(MONTH, DATEDIFF(MONTH, 0, Recording_Date), 0) Month_Start
, Sum(CASE WHEN Max_Temp <= 0 THEN 1 END) Max_Temp_Days
, Sum(CASE WHEN Min_Temp <= 0 THEN 1 END) Min_Temp_Days
, COUNT(*) Denominator
FROM TemperatureRecordings
WHERE Recording_Date BETWEEN '2013-01-01' AND '2013-03-31'
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Recording_Date), 0)
) t
ORDER BY Month_Start

This works for all month data
DECLARE #maxTempratureTable table(monthName varchar(20), [No. of days Max<=0] int,[Percentage Max <=0] float)
INSERT INTO maxTempratureTable
SELECT RIGHT(CONVERT(VARCHAR, Recording_date, 106), 8) ,
COUNT(*) ,
COUNT(*) / DAY(DATEADD(mm,DATEDIFF(mm,-1,Recording_date),-1)) * 100
FROM tablename
WHERE Max_Temp <=0
GROUP BY RIGHT(CONVERT(VARCHAR, Recording_date, 106), 8)
DECLARE #minTempratureTable table(monthName varchar(20), [No. of days Min<=0] int,[Percentage Min<=0] float)
INSERT INTO #minTempratureTable
SELECT RIGHT(CONVERT(VARCHAR, Recording_date, 106), 8) ,
COUNT(*) ,
COUNT(*) / DAY(DATEADD(mm,DATEDIFF(mm,-1,Recording_date),-1)) * 100
FROM tablename
WHERE Min_Temp <=0
GROUP BY RIGHT(CONVERT(VARCHAR, Recording_date, 106), 8)
SELECT * FROM #minTempratureTable min
INNER JOIN #maxTempratureTable max
ON min.monthName = max.monthName

SELECT
MONTH(Recording_date),
SUM(CASE WHEN Max_Temp <= 0 THEN 1 ELSE 0 END),
SUM(CASE WHEN Max_Temp <= 0 THEN 1 ELSE 0 END) / COUNT(*),
SUM( CASE WHEN Min_Temp <= 0 THEN 1 ELSE 0 END ),
SUM( CASE WHEN Min_Temp <= 0 THEN 1 ELSE 0 END ) / COUNT(*)
FROM temperatures
GROUP BY MONTH(Recording_date)

Related

How to derive new columns in YYYYMM format between two dates

I have following table
ID
Name
StartDate
EndDate
1
Aa
2021-10-14
2021-12-22
2
Ab
2021-12-02
2022-10-05
The requirement is to add new columns in YYYYMM format consisting of all the months between min(StartDate) and max(EndDate), and assign values to the corresponding cells. The cell value should be 1 if the date lies between StartDate and EndDate in that row, and should be 0 if it does not fall within that date range.The final output should be like in the below table
ID
Name
StartDate
EndDate
202110
202111
202112
202201
202202
202203
202204
202205
202206
202207
1
Aa
2021-10-14
2021-12-22
1
1
1
0
0
0
0
0
0
0
2
Ab
2021-12-02
2022-07-05
0
0
1
1
1
1
1
1
1
1
For the 1st row, since the startdate=2021-10-14 & EndDate=2021-12-22, corresponding new columns should be 202110,202111 & 202112; and corresponding cell values are 1 for these columns while the other cells are 0. Same logic should be applied to other rows as well.
I could not figure out the logic to derive new tables with new columns and corresponding cell values.
How about this approach using dynamic SQL:
CREATE TABLE Data ( ID INT, Name VARCHAR(100), StartDate DATE, EndDate DATE )
INSERT Data
VALUES
('1', 'Aa', '2021-10-14', '2021-12-22'),
('2', 'Ab', '2021-12-02', '2022-10-05')
-- Extract overall date range
DECLARE #MinStartDate DATE, #MaxEndDate AS DATE
SELECT #MinStartDate = MIN(StartDate), #MaxEndDate = MAX(EndDate)
FROM Data
-- Convert to months (DATETRUNC() may be used instead with SQL Server 2022 and later)
DECLARE #StartMonth DATE = DATEADD(day, 1 - DAY(#MinStartDate), #MinStartDate)
DECLARE #EndMonth DATE = DATEADD(day, 1 - DAY(#MaxEndDate), #MaxEndDate)
-- Generate calendar of months within range
DECLARE #Months TABLE ( Month DATE)
;WITH Months AS (
SELECT #StartMonth AS Month
UNION ALL
SELECT DATEADD(month, 1, M.Month)
FROM Months M
WHERE M.Month < #EndMonth
)
INSERT #Months
SELECT M.Month
FROM Months M
-- Define SQL Templates
DECLARE #SqlTemplate VARCHAR(MAX) = '
SELECT ID, Name, StartDate, EndDate
<ColumnSql>
FROM Data D
ORDER BY D.Name
'
DECLARE #ColumnTemplate VARCHAR(MAX) = '
, CASE WHEN D.StartDate <= <MonthEnd> AND <MonthStart> <= D.EndDate THEN 1 ELSE 0 END AS <ColumnName>'
-- Build month-specific column select items from template
DECLARE #ColumnSql VARCHAR(MAX) = (
SELECT STRING_AGG(C.ColumnSql, '') WITHIN GROUP(ORDER BY M.Month)
FROM #Months M
CROSS APPLY (
SELECT
CONVERT(CHAR(6), M.Month, 112) AS ColumnName,
M.Month AS MonthStart,
EOMONTH(M.Month) AS MonthEnd
) MD
CROSS APPLY (
SELECT REPLACE(REPLACE(REPLACE(
#ColumnTemplate
, '<ColumnName>', QUOTENAME(MD.ColumnName))
, '<MonthStart>', QUOTENAME(CONVERT(CHAR(8), MD.MonthStart, 112), ''''))
, '<MonthEnd>', QUOTENAME(CONVERT(CHAR(8), MD.MonthEnd, 112), ''''))
AS ColumnSql
) C
)
--SELECT #ColumnSql
-- Build final SQL
DECLARE #Sql VARCHAR(MAX) = REPLACE(#SqlTemplate, '<ColumnSql>', #ColumnSql)
SELECT #Sql
-- Deliver
EXEC (#Sql)
Generated SQL:
SELECT ID, Name, StartDate, EndDate
    , CASE WHEN D.StartDate <= '20211031' AND D.EndDate >= '20211001' THEN 1 ELSE 0 END AS [202110]
    , CASE WHEN D.StartDate <= '20211130' AND D.EndDate >= '20211101' THEN 1 ELSE 0 END AS [202111]
    , CASE WHEN D.StartDate <= '20211231' AND D.EndDate >= '20211201' THEN 1 ELSE 0 END AS [202112]
    , CASE WHEN D.StartDate <= '20220131' AND D.EndDate >= '20220101' THEN 1 ELSE 0 END AS [202201]
    , CASE WHEN D.StartDate <= '20220228' AND D.EndDate >= '20220201' THEN 1 ELSE 0 END AS [202202]
    , CASE WHEN D.StartDate <= '20220331' AND D.EndDate >= '20220301' THEN 1 ELSE 0 END AS [202203]
    , CASE WHEN D.StartDate <= '20220430' AND D.EndDate >= '20220401' THEN 1 ELSE 0 END AS [202204]
    , CASE WHEN D.StartDate <= '20220531' AND D.EndDate >= '20220501' THEN 1 ELSE 0 END AS [202205]
    , CASE WHEN D.StartDate <= '20220630' AND D.EndDate >= '20220601' THEN 1 ELSE 0 END AS [202206]
    , CASE WHEN D.StartDate <= '20220731' AND D.EndDate >= '20220701' THEN 1 ELSE 0 END AS [202207]
    , CASE WHEN D.StartDate <= '20220831' AND D.EndDate >= '20220801' THEN 1 ELSE 0 END AS [202208]
    , CASE WHEN D.StartDate <= '20220930' AND D.EndDate >= '20220901' THEN 1 ELSE 0 END AS [202209]
    , CASE WHEN D.StartDate <= '20221031' AND D.EndDate >= '20221001' THEN 1 ELSE 0 END AS [202210]
FROM Data D
ORDER BY D.Name
Results:
ID
Name
StartDate
EndDate
202110
202111
202112
202201
202202
202203
202204
202205
202206
202207
202208
202209
202210
1
Aa
2021-10-14
2021-12-22
1
1
1
0
0
0
0
0
0
0
0
0
0
2
Ab
2021-12-02
2022-10-05
0
0
1
1
1
1
1
1
1
1
1
1
1
See this db<>fiddle.
The above uses a standard test for date range overlap of "start1 <= end2 AND start2 <= end1", which assumes all dates are inclusive.

How can separate morning and evening shifts patients with gender wise using SQL stored procedure

I want to separate the morning and evening patient checked-in count gender-wise and also if gender age less then show the Female child and M child on the basis of gender.
SELECT
COUNT(ch.EnteredOn) AS counter,
CONVERT(date, ch.EnteredOn) AS sessionDay,
SUM(CASE WHEN CAST(CONVERT(CHAR(2), ch.EnteredOn, 108) AS INT) < 12 THEN 1 ELSE 0 END) AS 'Morning',
SUM(CASE WHEN CAST(CONVERT(CHAR(2), ch.EnteredOn, 108) AS INT) >= 12 THEN 1 ELSE 0 END) AS 'Evening',
SUM(CASE WHEN p.Gender = 1 THEN 1 ELSE 0 END) AS Male,
SUM(CASE WHEN p.Gender = 2 THEN 1 ELSE 0 END) AS Fmale,
SUM(CASE WHEN DATEDIFF(hour, P.DOB, GETDATE()) / 8766 <= 18
AND P.Gender = 1 THEN 1 ELSE 0 END) AS MChild,
SUM(CASE WHEN DATEDIFF(hour, P.DOB, GETDATE()) / 8766 <= 18
AND P.Gender = 2 THEN 1 ELSE 0 END) AS FChild
FROM
Patient.CheckIn ch
INNER JOIN
Patient.Patients P ON ch.PatientId = p.PatientId
GROUP BY
Ch.EnteredOn
I have only three columns like Gender, Time and DOB. Gender id 1 shows the male and Gender id 2 is using for females.
enter image description here
SELECT convert(date, ch.EnteredOn) AS sessionDay, CAST( CONVERT(CHAR(2), ch.EnteredOn, 108) AS INT) <12 as morning, count(ch.EnteredOn) AS counter
,sum(case when p.Gender=1 Then 1 ELSE 0 end) as Male
,sum(case when p.Gender=2 Then 1 ELSE 0 end) as Fmale
,Sum( case when DATEDIFF(hour,P.DOB,GETDATE())/8766<=18 AND P.Gender=1 Then 1 ELSE 0 end ) as MChiled
,Sum( case when DATEDIFF(hour,P.DOB,GETDATE())/8766<=18 AND P.Gender=2 Then 1 ELSE 0 end ) as FChiled
FROM Patient.CheckIn ch
inner join Patient.Patients P on ch.PatientId=p.PatientId
Group by Ch.EnteredOn
Group BY can be
Group by convert(date, ch.EnteredOn) AS sessionDay, CAST( CONVERT(CHAR(2), ch.EnteredOn, 108) AS INT) <12

Extract the percent days from a specific month

I have a table like this one - changes table:
Table 1:
id start_date end_date s_g r_c s_c
111 1/1/15 25/5/2015 A1 1 0
111 26/05/2015 31/12/9999 Z1 1 2
222 1/1/14 10/2/2015 Q1 1 0
222 11/2/2015 31/12/9999 R1 1 0
And I need to build an montly output for 2015 like this:
id month s_g r_c _s_c percent
111 1 A1 1 0 100%
111 2 A1 1 0 100%
111 3 A1 1 0 100%
111 4 A1 1 0 100%
111 5 A1 1 0 83.33%
111 5 Z1 1 2 16.67%
111 6 Z1 1 2 100%
111 7 Z1 1 2 100%
111 8 Z1 1 2 100%
222 1 Q1 1 0 100%
222 2 Q1 1 0 35.71%
222 2 R1 1 0 64.29%
222 3 R1 1 0 100%
222 4 R1 1 0 100%
222 5 R1 1 0 100%
222 6 R1 1 0 100%
222 7 R1 1 0 100%
222 8 R1 1 0 100%
I need this month only for year 2015.
Any idea how can I build this thing? just assum that those are the only case.
You could try this.
DECLARE #Month_2015 TABLE
(
Date1 Date,
Date2 Date
)
INSERT INTO #Month_2015
select '2015-01-01','2015-01-31'
union all
select '2015-02-01','2015-02-28'
union all
select '2015-03-01','2015-03-31'
union all
select '2015-04-01','2015-04-30'
union all
select '2015-05-01','2015-05-31'
union all
select '2015-06-01','2015-06-30'
...
With CTE as
(
Select ID, date1, s_g, r_c, s_c,
le = case when start_date < Date2 AND End_date > DATE1 THEN Datediff(d,
(case when start_date < date1 THEN date1 else start_date end),
(case when end_date < date2 THEN end_date else date2 end)
Else 0
end,
m = DATEDIFF (d, date1, date2)
from
Table1, #Month_2015
)
Select ID, Month(date1), s_g, r_c, s_c, (le*100.0 / m)
from CTE
Where le > 0
order by ID, Month(date1), s_g, r_c, s_c
Try this. It worked for me based on your table ##
DECLARE #TableRezult TABLE (id INT,month INT,s_g varchar(2),r_c INT,s_c INT, MonthPercentage varchar(25))
DECLARE #month INT=1
WHILE #month<=12
BEGIN
INSERT INTO #TableRezult
SELECT id,#month,s_g,r_c,s_c,
CASE WHEN (end_date >= dateadd(m,1,convert(varchar,#month)+'/1/2015') OR end_date='12/31/2015')
AND ([START_DATE]<=convert(varchar,#month)+'/1/2015') THEN '100%' ELSE
CASE WHEN end_date >= convert(varchar,#month)+'/1/2015' AND end_date < dateadd(m,1,convert(varchar,#month)+'/1/2015') THEN convert(VARCHAR ,Day(end_date)*100.0/DAY(EOMONTH(start_date)))+'%'
WHEN start_date >= convert(varchar,#month)+'/1/2015' AND start_date < dateadd(m,1,convert(varchar,#month)+'/1/2015') THEN convert(varchar,(DAY(EOMONTH(start_date))-Day(start_date))*100.0/DAY(EOMONTH(start_date)))+'%'
ELSE '0%' END
END FROM Table1 WHERE MONTH([START_DATE])<=#month AND MONTH(end_date)>=#month
SET #month=#month+1
END
SELECT * FROM #TableRezult ORDER BY id,[MONTH]
since it is not fully explain,i am posting half solution,after clearing doubts calculation can be corrected.
declare #Table1 table (id int,start_date datetime,end_date datetime
, s_g varchar(20), r_c int, s_c int )
insert into #Table1 values
(111 ,'2015-01-01','2015-5-25','A1', 1, 0 )
,(111 ,'2015-05-26','9999-12-31','Z1', 1, 2 )
,(222 ,'2014-01-01','2015-02-10','Q1', 1, 0 )
,(222 ,'2015-02-11','9999-12-31','R1', 1, 0 )
DECLARE #year INT = 2015
;WITH CTE
AS (
SELECT id
,s_g
,r_c
,s_c
,CASE
WHEN datepart(year, start_date) = #year
THEN start_date
WHEN datepart(year, start_date) < #year
THEN CAST(#year AS CHAR(4)) + '-' + '01' + '-' + '01'
WHEN datepart(year, start_date) > #year
THEN CAST(#year AS CHAR(4)) + '-' + '12' + '-' + '31'
END startdate
,CASE
WHEN datepart(year, end_date) = #year
THEN end_date
WHEN datepart(year, end_date) < #year
THEN CAST(#year AS CHAR(4)) + '-' + '01' + '-' + '01'
WHEN datepart(year, end_date) > #year
THEN CAST(#year AS CHAR(4)) + '-' + '12' + '-' + '31'
END enddate
FROM #table1
)
,CTE1
AS (
SELECT A.id
,A.s_g
,A.r_c
,A.s_c
,A.startdate
,A.enddate
,DATEPART(month, A.startdate) MonthList
FROM CTE A
UNION ALL
SELECT A.id
,A.s_g
,A.r_c
,A.s_c
,dateadd(month, 1, A.startdate)
,A.enddate
,a.MonthList + 1
FROM CTE1 A
WHERE A.MonthList < DATEPART(month, a.enddate)
)
--select * from cte1
SELECT *
,CASE
WHEN datediff(month, startdate, enddate) >= 1
THEN 100
ELSE (datepart(day, enddate) / cast(datepart(day, dateadd(day, - 1, dateadd(month, (datediff(month, 0, enddate) + 1), 0))) AS DECIMAL(4, 2))) * 100
END
FROM cte1
ORDER BY id
,s_g
,monthlist

SQL statement supposed to return more rows

My sql statement is a stored procedure that supposed to return the total scores which is grouped by each Agent (rawCSATAgentName)
this is my procedure:
ALTER PROCEDURE [dbo].[getCSATTeam]
#OtherDate DATE,
#DateToday DATE,
#FullNames nvarchar(MAX)
AS
BEGIN
SET NOCOUNT ON;
SELECT [rawCSATAgentName],
( CAST((SUM(case [rawCSATFCR] when 1 then 1 end) +
SUM(case [rawCSATFCR] when 0 then 0 when 2 then 0 end)) AS FLOAT)
/
(COUNT([rawCSATFCR])) * 100 ) AS [FCR],
( CAST((SUM(CASE WHEN [rawCSATHelpfulness] IN (6,7) THEN 1 END) +
SUM(CASE WHEN [rawCSATHelpfulness] IN (0,1,2,3,4,5) THEN 0 END)) AS FLOAT)
/
(COUNT([rawCSATHelpfulness])) * 100 )
AS [Helpfulness],
( CAST((SUM(CASE WHEN [rawCSATSAK] IN (6,7) THEN 1 END) +
SUM(CASE WHEN [rawCSATSAK] IN (0,1,2,3,4,5) THEN 0 END)) AS FLOAT)
/
(COUNT([rawCSATSAK])) * 100 )
AS [SkillsAndKnowledge],
( CAST((SUM(CASE WHEN [rawCSATOSR] IN (6,7) THEN 1 END) +
SUM(CASE WHEN [rawCSATOSR] IN (0,1,2,3,4,5) THEN 0 END)) AS FLOAT)
/
(COUNT([rawCSATOSR])) * 100 )
AS [OverallSatisfaction]
FROM [CSATScoresRaw]
WHERE (convert(varchar(10),[rawCSATDateTime],101) BETWEEN #OtherDate AND #DateToday)
AND [rawCSATAgentName] IN (SELECT i.str FROM dbo.iter$simple_strlist_to_tbl(#FullNames) AS i)
GROUP BY [rawCSATAgentName]
ORDER BY [rawCSATAgentName]
END
But it just return one [rawCSATAgentName] with the total scores. Why?

Syntax error in EXEC(#sql) in stored procedure

I'm coding a sp to use in an asp.net page which displays a gridview (with multiple pages) and checkboxes for the select query. However it gives me syntax error on the EXEC(#sql), can't I call it within the if after using the WITH...AS ?
SET #sql=#sql +' ' +' FROM DATASET WHERE (RowId BETWEEN (#page - 1) * #pageSize AND (#page) * #pageSize)
OR (#page IS NULL)'
if #filter='pt'
BEGIN
WITH DataSet AS
(
SELECT TOP 100 PERCENT
row_number() over(order by date desc) as 'RowId'
, convert(varchar(10), date 105) AS 'date'
, product1
, product2
, product3
, product4
, Y
, N
FROM (select date
, count(case when product='product1' then 1 else null end) as 'product1'
, count(case when product='product2' then 1 else null end) as 'product1'
, count(case when product='product3' then 1 else null end) as 'product1'
, count(case when onsale='Y' then 1 else null end) as 'Y'
, count(case when onsale='N' then 1 else null end) as 'N'
from dbo.vwSales
group by date) as o
WHERE
(date BETWEEN #from AND #to)
)
EXEC (#sql)
END
You have to have the whole SQL in the variable for the Exec -command, starting with the "with ...".
Unless there is something we're not seeing here, there is no reason to execute dynamic SQL here. Writing dynamic SQL and executing it with EXEC is generally an anti-pattern, as it opens you up to the possibility of writing some inefficient code with security problems.
Can you just run...
WITH DataSet AS
(
SELECT TOP 100 PERCENT
row_number() over(order by date desc) as 'RowId'
, convert(varchar(10), date 105) AS 'date'
, product1
, product2
, product3
, product4
, Y
, N
FROM (select date
, count(case when product='product1' then 1 else null end) as 'product1'
, count(case when product='product2' then 1 else null end) as 'product1'
, count(case when product='product3' then 1 else null end) as 'product1'
, count(case when onsale='Y' then 1 else null end) as 'Y'
, count(case when onsale='N' then 1 else null end) as 'N'
from dbo.vwSales
group by date) as o
WHERE
(date BETWEEN #from AND #to)
)
FROM DATASET WHERE (RowId BETWEEN (#page - 1) * #pageSize AND (#page) * #pageSize)
OR (#page IS NULL)
Also note that the "TOP 100 PERCENT" is unnecessary.

Resources