Max and min from the column in a table - sql-server

i have a table with the following data, i am trying to get the max and min columns from the table. if it is one column i can use max/min for the column, but here i am comparing all the column in a table. what i need is add new columns to store max and min data.
and there will be only one row in the table
create table
#test ( column1 int, column2 int , column3 int , column4 int ,column5 int,column6 int)
insert into #test
values( 89, 103,87,67,86,56)
select * from #test
--drop table #test
thanks in advance.

The easiest way to do this is just cross applying the min/max values of the columns. For example:
SELECT *
FROM #test t
CROSS APPLY (
SELECT MAX(val), MIN(val)
FROM (VALUES (t.column1), (t.column2), (t.column3), (t.column4), (t.column5), (t.column6)) AS c(val)
) AS c(maxvalue, minvalue);

Using the VALUES method to unpivot the data and then reaggravating it will make for a cleaner syntax but it does come with a cost to performance (not terrible but it is there). Using CASE expressions is a bit more cumbersome but in the syntax department, especially if there a lot of columns to be evaluated, but you won't incur the same performance penalty...
SELECT
t.column1, t.column2, t.column3, t.column4, t.column5, t.column6,
MinValue = CASE
WHEN t.column1 <= t.column2 AND t.column1 <= t.column3 AND t.column1 <= t.column4 AND t.column1 <= t.column5 AND t.column1 <= t.column6 THEN t.column1
WHEN t.column2 <= t.column1 AND t.column2 <= t.column3 AND t.column2 <= t.column4 AND t.column2 <= t.column5 AND t.column2 <= t.column6 THEN t.column2
WHEN t.column3 <= t.column1 AND t.column3 <= t.column2 AND t.column3 <= t.column4 AND t.column3 <= t.column5 AND t.column3 <= t.column6 THEN t.column3
WHEN t.column4 <= t.column1 AND t.column4 <= t.column2 AND t.column4 <= t.column3 AND t.column4 <= t.column5 AND t.column4 <= t.column6 THEN t.column4
WHEN t.column5 <= t.column1 AND t.column5 <= t.column2 AND t.column5 <= t.column3 AND t.column5 <= t.column4 AND t.column5 <= t.column6 THEN t.column5
ELSE t.column6
END,
MaxValue = CASE
WHEN t.column1 >= t.column2 AND t.column1 >= t.column3 AND t.column1 >= t.column4 AND t.column1 >= t.column5 AND t.column1 >= t.column6 THEN t.column1
WHEN t.column2 >= t.column1 AND t.column2 >= t.column3 AND t.column2 >= t.column4 AND t.column2 >= t.column5 AND t.column2 >= t.column6 THEN t.column2
WHEN t.column3 >= t.column1 AND t.column3 >= t.column2 AND t.column3 >= t.column4 AND t.column3 >= t.column5 AND t.column3 >= t.column6 THEN t.column3
WHEN t.column4 >= t.column1 AND t.column4 >= t.column2 AND t.column4 >= t.column3 AND t.column4 >= t.column5 AND t.column4 >= t.column6 THEN t.column4
WHEN t.column5 >= t.column1 AND t.column5 >= t.column2 AND t.column5 >= t.column3 AND t.column5 >= t.column4 AND t.column5 >= t.column6 THEN t.column5
ELSE t.column6
END
FROM
#test t;
Results...
column1 column2 column3 column4 column5 column6 MinValue MaxValue
----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
89 103 87 67 86 56 56 103

I found this solution here.
SELECT
column1
,column2
,column3
,column4
,column5
,column6
,(SELECT MAX(MaxValue)
FROM (VALUES (column1),(column2),(column3), (column4), (column5), (column6)) AS [Values](MaxValue))
AS MaxValue
,(SELECT MIN(MinValue)
FROM (VALUES (column1),(column2),(column3), (column4), (column5), (column6)) AS [Values](MinValue))
AS MinValue
FROM #test

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.

Simplyfing update query with case when

I have a query where there is a lot of repetitions of one condition. I am wondering - is it possible to put this condition into variable or something like that, so not the whole sentence is repeated each time?
The part which is repeating:
ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR
WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0)
In query it looks like this:
UPDATE #tblALL_HOURS SET REG_WORK_COST = (CASE WHEN MINUTE_FROM >= 0 AND MINUTE_FROM <= #6h AND MINUTE_TO >= #6h AND MINUTE_TO <= #18h
AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATEADD(MINUTE, #6h, CAST(CAST(DATE_TO AS DATE) AS DATETIME)), date_to)/60.00) * (BRUTO_HOUR + ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0))
WHEN MINUTE_FROM >= 0 AND MINUTE_FROM <= #6h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h
AND IS_ABSENT = 0
THEN 12.00 * (BRUTO_HOUR + ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0))
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #6h AND MINUTE_TO <= #18h
AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATE_FROM, DATE_TO) / 60.00) * (BRUTO_HOUR + ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0))
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h
AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATE_FROM, DATEADD(MINUTE, #18h, CAST(CAST(DATE_FROM AS DATE) AS DATETIME))) / 60.00) * (BRUTO_HOUR + ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0))
END)
Is it possible to have something like this instead:
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h AND IS_ABSENT = 0 THEN (DATEDIFF(MINUTE, DATE_FROM, DATEADD(MINUTE, #18h, CAST(CAST(DATE_FROM AS DATE) AS DATETIME))) / 60.00) * (BRUTO_HOUR + #myCondition)
Use a simple CTE that returns all the columns of #tblALL_HOURS and the value returned by ISNULL function:
ISNULL(CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END,0)
as a column and then update With the CTE and use that column in place of the condition:
WITH cte AS (
SELECT *,
ISNULL(CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END,0) AS myCondition
FROM #tblALL_HOURS
)
UPDATE cte
SET REG_WORK_COST = CASE
WHEN MINUTE_FROM >= 0 AND MINUTE_FROM <= #6h AND MINUTE_TO >= #6h AND MINUTE_TO <= #18h AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATEADD(MINUTE, #6h, CAST(CAST(DATE_TO AS DATE) AS DATETIME)), date_to)/60.00) * (BRUTO_HOUR + myCondition)
WHEN MINUTE_FROM >= 0 AND MINUTE_FROM <= #6h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h AND IS_ABSENT = 0
THEN 12.00 * (BRUTO_HOUR + myCondition)
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #6h AND MINUTE_TO <= #18h AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATE_FROM, DATE_TO) / 60.00) * (BRUTO_HOUR + myCondition)
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATE_FROM, DATEADD(MINUTE, #18h, CAST(CAST(DATE_FROM AS DATE) AS DATETIME))) / 60.00) * (BRUTO_HOUR + myCondition)
END

how to make multi column with multi where condition

i have 3 SQL statement i want to merge them into one but each of them has its own where condition how can i merge them into one query that show the result for each of them to be like
Project Code||Balance||Salaries||Materials
1st
SELECT
ProjectCode,
SUM (- 1 *(CreditAm) +(DebitAm)) AS Balance
FROM
[dbo].[AcDetail]
WHERE
AcCode IN (
401000,
402000,
403000,
404000,
405000,
406000,
407000,
499999
)
AND BranchCode = 'WP'
AND TDate >= '2016-01-01'
AND TDate <= '2016-12-31'
GROUP BY
ProjectCode
2nd
SELECT
ProjectCode,
SUM (- 1 *(CreditAm) +(DebitAm)) AS Materials
FROM
[dbo].[AcDetail]
WHERE
AcCode IN (600001, 600002, 600151)
AND BranchCode = 'WP'
AND TDate >= '2016-01-01'
AND TDate <= '2016-12-31'
GROUP BY
ProjectCode
3rd
SELECT
ProjectCode,
SUM (- 1 *(CreditAm) +(DebitAm)) AS Salaries
FROM
[dbo].[AcDetail]
WHERE
AcCode IN (
650001,
650005,
650006,
650007,
650008,
650009,
650010,
650020,
650021,
650022,
650023,
650024,
650025,
650026,
650027
)
AND BranchCode = 'WP'
AND TDate >= '2016-01-01'
AND TDate <= '2016-12-31'
GROUP BY
ProjectCode
ORDER BY
ProjectCode
Use Conditional SUM. Sum the values only when the Accode matches the list
SELECT ProjectCode,
Sum (CASE
WHEN AcCode IN ( '401000', '402000', '403000', '404000',
'405000', '406000', '407000', '499999' ) THEN -1 * ( CreditAm ) + ( DebitAm )
ELSE 0
END) AS Balance,
Sum (CASE
WHEN AcCode IN ( '600001', '600002', '600151' ) THEN -1 * ( CreditAm ) + ( DebitAm )
ELSE 0
END) AS Materials,
Sum (CASE
WHEN AcCode IN ( '650001', '650005', '650006', '650007',
'650008', '650009', '650010', '650020',
'650021', '650022', '650023', '650024',
'650025', '650026', '650027' ) THEN -1 * ( CreditAm ) + ( DebitAm )
ELSE 0
END) AS Salaries
FROM [dbo].[AcDetail]
WHERE AcCode IN ( '401000', '402000', '403000', '404000',
'405000', '406000', '407000', '499999',
'600001', '600002', '600151', '650001',
'650005', '650006', '650007', '650008',
'650009', '650010', '650020', '650021',
'650022', '650023', '650024', '650025',
'650026', '650027' )
GROUP BY ProjectCode
We can done it using OUTER APPLY as well by making different set for each column as below:
SELECT D.ProjectCode,
ISNULL(SUM(B.Balance), 0) AS Balance,
ISNULL(SUM(M.Materials), 0) AS Materials,
ISNULL(SUM(S.Salaries), 0) AS Salaries
FROM [dbo].[AcDetail] AS D
OUTER APPLY (SELECT (- 1 *(CreditAm) +(DebitAm)) AS Balance
FROM [dbo].[AcDetail]
WHERE AcCode IN ('401000', '402000', '403000', '404000',
'405000', '406000', '407000', '499999')
AND AcCode = D.AcCode
AND TDate = D.TDate
AND ProjectCode = D.ProjectCode) AS B --Balance
OUTER APPLY (SELECT (- 1 *(CreditAm) +(DebitAm)) AS Materials
FROM [dbo].[AcDetail]
WHERE AcCode IN ('600001', '600002', '600151')
AND AcCode = D.AcCode
AND TDate = D.TDate
AND ProjectCode = D.ProjectCode) AS M -- Materials
OUTER APPLY (SELECT (- 1 *(CreditAm) +(DebitAm)) AS Salaries
FROM [dbo].[AcDetail]
WHERE AcCode IN ('650001', '650005', '650006', '650007', '650008', '650009',
'650010', '650020','650021', '650022', '650023', '650024',
'650025', '650026', '650027')
AND AcCode = D.AcCode
AND TDate = D.TDate
AND ProjectCode = D.ProjectCode) AS S --Salary
WHERE D.BranchCode = 'WP'
AND D.AcCode IN ('401000', '402000', '403000', '404000', '405000', '406000', '407000',
'499999','600001', '600002', '600151', '650001', '650005', '650006', '650007',
'650008','650009', '650010', '650020', '650021', '650022', '650023', '650024',
'650025','650026', '650027')
AND D.TDate >= '2016-01-01'
AND D.TDate <= '2016-12-31'
GROUP BY D.ProjectCode
ORDER BY D.ProjectCode

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

Take the first line of the every partition

I have this query :
select ROW_NUMBER() OVER ( PARTITION BY codtiers ORDER BY case when isnull(cumulapport, 0) > isnull(cumulretrait, 0) then cumulapport
else cumulretrait
end DESC ) AS classement,
codTiers
from dbo.TiersComptesLocal
group by codTiers
which return this result :
classement | codTiers
-------------------------
1 | 1XXXXX
2 | 1XXXXX
1 | 1YYXXX
2 | 1YYXXX
3 | 1YYXXX
1 | 1XXXYY
I want to display the first line from every partition
I want to have a result like this :
classement | codTiers
-------------------------
1 | 1XXXXX
1 | 1YYXXX
1 | 1XXXYY
Any idea will be appreciate.
this is my full query :
select ROW_NUMBER() OVER ( PARTITION BY tcl_codtiers ORDER BY case when isnull(cumulapport, 0) > isnull(cumulretrait, 0) then cumulapport
else cumulretrait
end DESC ) AS classement,
TCL_CodTiers,
'le montant max des ' + Senscumul + ' ( '
+ convert(varchar(50), '') + ' € ) du tiers titulaire '
+ TCL_CodTiers + ' ( ' + ''
+ ' ) est supérieur au seuil fixé dans l''alerte : '
+ '75000'
from dbo.CLI_TCL_TiersComptesLocal
INNER JOIN dbo.CLI_GCO_GeneriquesComptes ON TCL_CodTiers = GCO_CodTiersPrincipal
AND TCL_NumLien IN ( 0, 1 )
inner join ( select TCL_CodTiers CodTiers,
sum(case when ESO_MntValoRetenuEnEuros > 0
then ESO_MntValoRetenuEnEuros
else 0
end) cumulapport,
sum(case when ESO_MntValoRetenuEnEuros < 0
then abs(ESO_MntValoRetenuEnEuros)
else 0
end) cumulretrait,
case when isnull( sum(case when ESO_MntValoRetenuEnEuros > 0
then ESO_MntValoRetenuEnEuros
else 0
end), 0) > isnull( sum(case when ESO_MntValoRetenuEnEuros < 0
then abs(ESO_MntValoRetenuEnEuros)
else 0
end), 0)
then 'Apports'
else 'Retraits'
end as Senscumul
from CRO_ESO_EntreeSortie
inner join CLI_TCL_TiersComptesLocal on TCL_CodCompte = ESO_CodCompte
and TCL_NumLien in ( 0, 1 )
group by TCL_CodTiers
having sum(case when ESO_MntValoRetenuEnEuros > 0
then ESO_MntValoRetenuEnEuros
else 0
end) > 75000
or sum(case when ESO_MntValoRetenuEnEuros < 0
then abs(ESO_MntValoRetenuEnEuros)
else 0
end) > 75000
) surveillance on GCO_CodTiersPrincipal = CodTiers
Thanks in advance.
No idea why you don't want to use a CTE, but you can use a derived table if you want, though it still is basically the same answer that Mahmoud already posted:
SELECT *
FROM (SELECT ROW_NUMBER() OVER (PARTITION BY codtiers
ORDER BY CASE WHEN ISNULL(cumulapport, 0)>ISNULL(cumulretrait, 0)
THEN cumulapport ELSE cumulretrait END DESC) AS classement,
codTiers
FROM dbo.TiersComptesLocal
GROUP BY codTiers) A
WHERE classement = 1
Here is a solution without using WITH - though I'm not sure why that is a problem.
SELECT classement, codtiers
FROM
(
SELECT
classement = ROW_NUMBER() OVER (PARTITION BY codtiers
ORDER BY CASE WHEN ISNULL(cumulapport, 0) > ISNULL(cumulretrait, 0)
THEN cumulapport ELSE cumulretrait END DESC),
codTiers
FROM dbo.TiersComptesLocal
) AS x
WHERE classement = 1;
WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY codtiers
ORDER BY CASE
WHEN ISNULL(cumulapport, 0) >
ISNULL(cumulretrait, 0) THEN cumulapport
ELSE cumulretrait
END DESC) AS classement,
codTiers
FROM dbo.TiersComptesLocal
)
SELECT *
FROM CTE
WHERE classement = 1;
Update
You can't filter on that column classement in the same query, you have to use a CTE or a subquery instead like in #AaronBertrand answer. However, if you want to do this in the same query, you have to do this without ROW_NUMBER():
SELECT
codtiers,
MAX(CASE
WHEN ISNULL(cumulapport, 0) >
ISNULL(cumulretrait, 0) THEN cumulapport
ELSE cumulretrait
END DESC) AS classement
FROM dbo.TiersComptesLocal
GROUP BY codtiers;

Resources