Pivoting a table-valued function - sql

I have a TVF that returns two columns: 'measure' (a name) and 'score', a numeric score for that measure:
dbo.ScoringFunction(param1, param2, ..., paramN)
Measure Score
------- -----
measure1 10
measure2 5
... ...
measureN 15
I'm running this function against a large number of rows that contain its parameters:
Name Param1 Param2 ... ParamN
---- ------ ------ ------
Daniel 12 5 6
etc.
I am trying to find a way to display the measures and their scores next to the parameters that determine those scores:
Name Param1 Param2 ... ParamN measure1 measure2 ... measureN
---- ------ ------ ------ -------- -------- --------
Daniel 12 5 6 10 5 15
etc.
So far I have tried using a pivot table, but it's tricky since the data being pivoted is contained in a TVF rather than a static table. I've also tried using CROSS APPLY, but once I have the data (measures & scores), I'm still unable to pivot it into a nicely formatted row.
If anybody has any ideas, they would be much appreciated!

Without changing too much (hopefully), I would do the pivoting in the function, then use the function in CROSS APPLY and pull the columns. So if your function is something like this:
CREATE FUNCTION dbo.ScoringFunction (parameters)
RETURNS TABLE
RETURN (
SELECT Measure, Score
FROM …
)
then I would rewrite it like this:
CREATE FUNCTION dbo.ScoringFunction (parameters)
RETURNS TABLE
RETURN (
WITH originalSelect AS (
SELECT Measure, Score
FROM …
)
SELECT
measure1,
measure2,
…
FROM originalSelect
PIVOT (
MAX(Score) FOR Measure IN (measure1, measure2, …)
) p
)
and use it in the final query like this:
SELECT
t.Name,
t.param1,
t.param2,
…
x.measure1,
x.measure2,
…
FROM atable t
CROSS APPLY dbo.ScoringFunction (t.param1, t.param2, …) x

If you make a function that looks like this:
CREATE FUNCTION [dbo].[fGetSpecificMeasures]
(
#HeightScore INT
, #WeightScore INT
, #TvScore INT
)
RETURNS TABLE
RETURN
(
SELECT
Final.Height AS tv_height_score
, Final.[Weight] AS tv_weight_score
, Final.TV AS tv_score
FROM
(
SELECT measure, score FROM ScoringRubric WHERE measure = 'Height' AND #HeightScore BETWEEN bottom_of_range AND top_of_range
UNION ALL
SELECT measure, score FROM ScoringRubric WHERE measure = 'Weight' AND #WeightScore BETWEEN bottom_of_range AND top_of_range
UNION ALL
SELECT measure, score FROM ScoringRubric WHERE measure = 'TV' AND #TvScore BETWEEN bottom_of_range AND top_of_range
) Base
PIVOT
(
MAX(score)
FOR measure
IN
(
[Height]
, [Weight]
, [TV]
)
) Final
);
GO
And one that looks like this:
CREATE FUNCTION [dbo].[fGetMeasureScore]
(
#Measure VARCHAR(50)
, #Value INT
)
RETURNS TABLE
RETURN
(
SELECT
score
FROM ScoringRubric
WHERE measure = #Measure
AND #Value BETWEEN bottom_of_range AND top_of_range
);
GO
Then you can get your data with either of the following:
DECLARE #User VARCHAR(50) = 'Daniel'
SELECT
UserProfile.*
, HeightScore.score AS tv_height_score
, WeightScore.score AS tv_weight_score
, TvScore.score AS tv_score
FROM UserProfile
INNER JOIN ScoringRubric HeightScore
ON HeightScore.measure = 'Height'
AND UserProfile.height BETWEEN HeightScore.bottom_of_range AND HeightScore.top_of_range
INNER JOIN ScoringRubric WeightScore
ON WeightScore.measure = 'Weight'
AND UserProfile.[weight] BETWEEN WeightScore.bottom_of_range AND WeightScore.top_of_range
INNER JOIN ScoringRubric TvScore
ON TvScore.measure = 'TV'
AND UserProfile.TV BETWEEN TvScore.bottom_of_range AND TvScore.top_of_range
WHERE UserProfile.name = #User
SELECT
*
FROM UserProfile
CROSS APPLY dbo.fGetSpecificMeasures(height, [weight], TV)
WHERE name = #User
SELECT
UP.*
, HeightScore.score AS tv_height_score
, WeightScore.score AS tv_weight_score
, TvScore.score AS tv_score
FROM UserProfile UP
CROSS APPLY fGetMeasureScore('Height', UP.height) HeightScore
CROSS APPLY fGetMeasureScore('Weight', UP.[weight]) WeightScore
CROSS APPLY fGetMeasureScore('TV', UP.TV) TvScore
WHERE UP.name = #User
I don't really know which one you'll find most appropriate for your uses. Let me know if you have questions.
As for your original question, if this were the function:
CREATE FUNCTION [dbo].[fGetMeasureScoresOriginal]
(
#HeightScore INT
, #WeightScore INT
, #TvScore INT
)
RETURNS TABLE
RETURN
(
SELECT measure, score FROM ScoringRubric WHERE measure = 'Height' AND #HeightScore BETWEEN bottom_of_range AND top_of_range
UNION ALL
SELECT measure, score FROM ScoringRubric WHERE measure = 'Weight' AND #WeightScore BETWEEN bottom_of_range AND top_of_range
UNION ALL
SELECT measure, score FROM ScoringRubric WHERE measure = 'TV' AND #TvScore BETWEEN bottom_of_range AND top_of_range
)
GO
Then you could write the query and pivot like so:
SELECT
Final.name
, Final.OriginalHeight AS height
, Final.OriginalWeight AS [weight]
, Final.OriginalTv AS TV
, Final.Height AS tv_height_score
, Final.[Weight] AS tv_weight_score
, Final.TV AS tv_score
FROM
(
SELECT
UP.name
, UP.height AS OriginalHeight
, UP.[weight] AS OriginalWeight
, UP.TV AS OriginalTv
, Measures.measure
, Measures.score
FROM UserProfile UP
CROSS APPLY dbo.fGetMeasureScoresOriginal(UP.height, UP.[weight], UP.TV) Measures
WHERE UP.name = #User
) Base
PIVOT
(
MAX(score)
FOR measure
IN
(
[Height]
, [Weight]
, [TV]
)
) Final
EDIT: Just realized I didn't answer the original question. Adding that now.

If you want to pivot a static set of rows you can use the technique as I described here.
Reposting the example, so it will be different tables, but the technique can be applied in your case as well I think.
SELECT
Customers.CustID,
MAX(CASE WHEN CF.FieldID = 1 THEN CF.FieldValue ELSE NULL END) AS Field1,
MAX(CASE WHEN CF.FieldID = 2 THEN CF.FieldValue ELSE NULL END) AS Field2,
MAX(CASE WHEN CF.FieldID = 3 THEN CF.FieldValue ELSE NULL END) AS Field3,
MAX(CASE WHEN CF.FieldID = 4 THEN CF.FieldValue ELSE NULL END) AS Field4
-- Add more...
FROM Customers
LEFT OUTER JOIN CustomFields CF
ON CF.ID = Customers.CustID
WHERE Customers.CustName like 'C%'
GROUP BY Customers.CustID

Related

Transpose row to column in SQL Server

I have a table like below:
Type PKG_HA_01_ON PKG_HA_03_ON PKG_HA_04_ON PKG_HA_05_ON PKG_HA_06_ON PKG_HA_09_ON
duration 18.6694 60 15.1951 56.2068 13.6808 13.8404
counter 5 0 5 11 2 0
The first row is the header. Now, I would like to transpose table into this
Machine Duration Counter
PKG_HA_01_ON 18.6694 5
PKG_HA_03_ON 60 0
...
I have tried unpivot but the result is not desired table.
Thanks in advance,
Try this:
create table unpivot_raw(
[Type] nvarchar(255)
, PKG_HA_01_ON float null
, PKG_HA_03_ON float null
, PKG_HA_04_ON float null
, PKG_HA_05_ON float null
, PKG_HA_06_ON float null
, PKG_HA_09_ON float null
)
insert into unpivot_raw
select 'duration', 18.6694, 60, 15.1951, 56.2068, 13.6808, 13.8404
union
select 'counter', 5, 0, 5, 11, 2, 0
select
*
from
(
select
[Type]
, vl
, Machine
from
(
select
[Type]
, PKG_HA_01_ON
, PKG_HA_03_ON
, PKG_HA_04_ON
, PKG_HA_05_ON
, PKG_HA_06_ON
, PKG_HA_09_ON
from unpivot_raw
) p
unpivot
(
vl for Machine in
(
PKG_HA_01_ON
, PKG_HA_03_ON
, PKG_HA_04_ON
, PKG_HA_05_ON
, PKG_HA_06_ON
, PKG_HA_09_ON
)
) unpvt
) base
pivot
(
max(vl) for [Type] in (duration, counter )
) pvt
I recommend using cross apply to unpivot and then aggregation:
select machine,
max(case when type = 'duration' then val end) as duration,
max(case when type = 'counter' then val end) as counter
from t cross apply
(values ('PKG_HA_01_ON', PKG_HA_01_ON),
('PKG_HA_03_ON', PKG_HA_03_ON),
('PKG_HA_04_ON', PKG_HA_04_ON),
('PKG_HA_05_ON', PKG_HA_05_ON),
('PKG_HA_06_ON', PKG_HA_06_ON),
('PKG_HA_09_ON', PKG_HA_09_ON)
) v(machine, val)
group by machine;
I much, much prefer this over pivot/unpivot. Why? APPLY implements a lateral join, which is a powerful construct in SQL (and part of the SQL standard albeit with slightly different syntax). Unpivoting is a nice introduction to this feature.
The pivoting functions are bespoke functions and not part of the standard. They also do not generalize in any way, being designed for a single purpose.

T-SQL - Copying & Transposing Data

I'm trying to copy data from one table to another, while transposing it and combining it into appropriate rows, with different columns in the second table.
First time posting. Yes this may seem simple to everyone here. I have tried for a couple hours to solve this. I do not have much support internally and have learned a great deal on this forum and managed to get so much accomplished with your other help examples. I appreciate any help with this.
Table 1 has the data in this format.
Type Date Value
--------------------
First 2019 1
First 2020 2
Second 2019 3
Second 2020 4
Table 2 already has the Date rows populated and columns created. It is waiting for the Values from Table 1 to be placed in the appropriate column/row.
Date First Second
------------------
2019 1 3
2020 2 4
For an update, I might use two joins:
update t2
set first = tf.value,
second = ts.value
from table2 t2 left join
table1 tf
on t2.date = tf.date and tf.type = 'First' left join
table1 ts
on t2.date = ts.date and ts.type = 'Second'
where tf.date is not null or ts.date is not null;
use conditional aggregation
select date,max(case when type='First' then value end) as First,
max(case when type='Second' then value end) as Second from t
group by date
You can do conditional aggregation :
select date,
max(case when type = 'first' then value end) as first,
max(case when type = 'Second' then value end) as Second
from table t
group by date;
After that you can use cte :
with cte as (
select date,
max(case when type = 'first' then value end) as first,
max(case when type = 'Second' then value end) as Second
from table t
group by date
)
update t2
set t2.First = t1.First,
t2.Second = t1.Second
from table2 t2 inner join
cte t1
on t1.date = t2.date;
Seems like you're after a PIVOT
DECLARE #Table1 TABLE
(
[Type] NVARCHAR(100)
, [Date] INT
, [Value] INT
);
DECLARE #Table2 TABLE(
[Date] int
,[First] int
,[Second] int
)
INSERT INTO #Table1 (
[Type]
, [Date]
, [Value]
)
VALUES ( 'First', 2019, 1 )
, ( 'First', 2020, 2 )
, ( 'Second', 2019, 3 )
, ( 'Second', 2020, 4 );
INSERT INTO #Table2 (
[Date]
)
VALUES (2019),(2020)
--Show us what's in the tables
SELECT * FROM #Table1
SELECT * FROM #Table2
--How to pivot the data from Table 1
SELECT * FROM #Table1
PIVOT (
MAX([Value]) --Pivot on this Column
FOR [Type] IN ( [First], [Second] ) --Make column where [Value] is in one of this
) AS [pvt] --Table alias
--which gives
--Date First Second
------------- ----------- -----------
--2019 1 3
--2020 2 4
--Using that we can update #Table2
UPDATE [tbl2]
SET [tbl2].[First] = pvt.[First]
,[tbl2].[Second] = pvt.[Second]
FROM #Table1 tbl1
PIVOT (
MAX([Value]) --Pivot on this Column
FOR [Type] IN ( [First], [Second] ) --Make column where [Value] is in one of this
) AS [pvt] --Table alias
INNER JOIN #Table2 tbl2 ON [tbl2].[Date] = [pvt].[Date]
--Results from #Table 2 after updated
SELECT * FROM #Table2
--which gives
--Date First Second
------------- ----------- -----------
--2019 1 3
--2020 2 4

Pivot outputs two values

create table #Contact(
LoanNumber int,
ContactType varchar(10),
CompanyName varchar(10),
CompanyPhone varchar(10),
CONSTRAINT PK PRIMARY KEY (LoanNumber,ContactType)
)
Insert into #Contact
values (1,'Appriaser','Yige King','11' ),
(1,'AssetOwner','gqqnbig','22' )
This is my table. ContactTypes are only Appriaser and AssetOwner.
Can I get a table like
LoanNumber AppraiserCompanyName AppraiserCompanyPhone AssertOwnerCompanyName AssertOwnerCompanyPhone
----------------------------------------------------------------------------------------------------
6103339 YigeKing 11 gqqnbig 22
I managed to write this
select LoanNumber,
CompanyNamePT.Appriaser as AppriaserCompanyName, CompanyNamePT.AssetOwner as AssetOwnerCompanyName
--CompanyPhonePT.Appriaser as AppriaserCompanyPhone, CompanyPhonePT.AssetOwner as AssetOwnerCompanyPhone
from (
select #contact.LoanNumber, #contact.ContactType, #contact.CompanyName
from #contact
) as c
pivot ( max(c.CompanyName) for c.ContactType in (Appriaser,AssetOwner)) as CompanyNamePT
--pivot ( max(c.CompanyPhone) for c.ContactType in ([Appriaser],[AssetOwner])) as CompanyPhonePT
It outputs company names, but if I uncomment the two lines to get phone number, it throws syntax error.
How can I make it work? Ideally I want to use pivot because I'm learnig it.
For the desired PIVOT
Select *
From (
Select C.LoanNumber
,B.*
From #Contact C
Cross Apply ( values (IIF(ContactType='Appriaser' ,'AppraiserCompanyName' , 'AssetOwnerCompanyName') ,C.CompanyName)
,(IIF(ContactType='Appriaser' , 'AppraiserCompanyPhone', 'AssetOwnerCompanyPhone'),C.CompanyPhone)
) B (Item,Value)
) A
pivot ( max(A.Value) for A.Item in ([AppraiserCompanyName],[AppraiserCompanyPhone],[AssetOwnerCompanyName],[AssetOwnerCompanyPhone]) ) P
But a Conditional Aggregation would do as well
Select C.LoanNumber
,AppraiserCompanyName = max(case when ContactType='Appriaser' then C.CompanyName end)
,AppraiserCompanyPhone = max(case when ContactType='Appriaser' then C.CompanyPhone end)
,AssetOwnerCompanyName = max(case when ContactType='AssetOwner' then C.CompanyName end)
,AssetOwnerCompanyPhone = max(case when ContactType='AssetOwner' then C.CompanyPhone end)
From #Contact C
Group By C.LoanNumber
Both Would Return
If it Helps with the Visualization, the sub-query with the Cross Apply Generates

IFS and INDEX/ MATCH EXCEL COUNTERPART IN SQL QUERY

My table looks like this
NAME BRAND REFERENCE COMMENTS <-Expected output
-------------------------------------------------
Gu Skirt 101128 Pants
Cci Pants 101127 Pants
Cha Skirt paired paired
Gu Pants 101128 Skirts
Nel Skirt nonpaired UNIQUE
Gir Pants 101188 Skirt
Baud Skirt dropped DROPPED
Le Pants paired PAIRED
Gir Skirt 101188 101178
Vis Socks blanks
Cci Skirts 101127 Skirts
I wonder what code to use to get the Comments result.
First reference in NUMBERS should be paired. If reference numbers match, return value should be the Brand counterpart.
If reference is in Character, they have to fall under if statements: IF character is Nonpaired return value should be unique, dropped for dropped and so on. If the reference is blanks no change.
Is this possible?
Thank you so much.
You can use common table expressions to break down the problem which can help with maintaining the code.
I didn't use lag/lead because you only have two rows in the pair, so numbering the rows and joining the table to itself felt quicker and easier to follow.
Here's the code I've used to answer and test your question;
create table #source
(
[NAME] varchar(200),
[BRAND] varchar(200),
[REFERENCE] varchar(200)
);
insert into #source values
('Gu','Skirt','101128'),
('Cci','Pants','101127'),
('Cha','Skirt','paired'),
('Gu','Pants','101128'),
('Nel','Skirt','nonpaired'),
('Gir','Pants','101188'),
('Baud','Skirt','dropped'),
('Le','Pants','paired'),
('Gir','Skirt','101188'),
('Vis','Socks',''),
('Cci','Skirts','101127'),
('Le','Socks','101188'),
('Uno','Socks','101101');
select * from #source;
with cteNumericRef as
(
select [NAME],[BRAND],[REFERENCE]
from #source
where ISNUMERIC([REFERENCE]) = 1
)
, cteCheckRow as
(
select [REFERENCE],
'CHECK' as [COMMENT]
from cteNumericRef
group by [REFERENCE]
having count(*) <> 2
)
, ctePairedRow as
(
select
num_ref.[NAME]
, num_ref.[BRAND]
, num_ref.[REFERENCE]
, row_number() over (partition by num_ref.[REFERENCE] order by num_ref.[NAME]) as [Pair_Num]
from cteNumericRef num_ref
left join cteCheckRow check_row
on check_row.[REFERENCE] = num_ref.[REFERENCE]
where check_row.[REFERENCE] is null
)
, cteTextRow as
(
select [NAME],[BRAND],[REFERENCE],
case [REFERENCE]
when 'paired' then 'PAIRED'
when 'nonpaired' then 'UNIQUE'
when 'dropped' then 'DROPPED'
when '' then ''
else 'CHECK' end as [COMMENT]
from #source
where ISNUMERIC([REFERENCE]) <> 1
)
select
left_row.[NAME]
, left_row.[BRAND]
, left_row.[REFERENCE]
, right_row.[BRAND] as [COMMENTS]
from ctePairedRow left_row
inner join ctePairedRow right_row
on left_row.[REFERENCE] = right_row.[REFERENCE]
and left_row.[Pair_Num] <> right_row.[Pair_Num]
union all
select
num_ref.[NAME]
, num_ref.[BRAND]
, num_ref.[REFERENCE]
, check_row.[COMMENT]
from cteNumericRef num_ref
inner join cteCheckRow check_row
on check_row.[REFERENCE] = num_ref.[REFERENCE]
union all
select
[NAME]
, [BRAND]
, [REFERENCE]
, [COMMENT]
from cteTextRow;
drop table #source
SELECT Name,
Brand,
Reference,
CASE WHEN Reference = 'Paired' THEN 'Paired'
WHEN Reference = 'nonpaired' THEN 'Unique'
WHEN Reference = 'dropped' THEN 'DROPPED'
WHEN Reference = ' ' THEN 'blanks'
WHEN Reference = Next_Ref AND rownum = 1 THEN next_brand
WHEN Reference = Prev_Ref AND rownum = 2 THEN prev_brand
END AS Comments
FROM
(
SELECT Name,
Brand,
Reference,
LAG( Reference, 1 )OVER PARTITION BY ( Reference ORDER BY Brand ) AS Prev_Ref,
LEAD( Reference, 1 )OVER PARTITION BY ( Reference ORDER BY Brand ) AS Next_Ref,
LAG( Brand, 1 ) OVER PARTITION BY ( Reference ORDER BY Brand ) AS Prev_Brand,
LEAD( Brand, 1 ) OVER PARTITION BY ( Reference ORDER BY Brand ) AS Next_Brand,
ROW_NUMBER( ) OVER PARTITION BY ( Reference ORDER BY Brand ) AS rownum
FROM Data
);

Summary Stats and Corresponding Dates - SQL Server

I was hoping someone perhaps could help. This problem was presented to me recently and I thought it would be easy, but (personally) found it a bit of a struggle. I can do it in Excel and SSRS - but I was curious if I was able to do it in SQL Server...
I would like to create a set of summary statistics (Max, Min) for a dataset. Easy enough... But I wanted to associate the corresponding date with those values.
Here is what my data looks like:
I have yearly data (not exactly - but beside the point) and I produce a pivoted summary like this using a series of CASE WHEN statements. This is fine - the output is seen on the right (above).
Each time I output this data - I like to provide a summary of the all the historic data (I only show the most recent data for sake of brevity). So... The question is how do I take an output like the one shown below (on different dates) and provide a summary data set like the one I have on the right?
So - a little background. I have already managed to join the Min and Max values using a UNION and that bit is fine. The tricky bit (I think) is how to form an INNER JOIN, using a sub query, with the Max or Min result values to return the corresponding Max or Min date, for each Type? Now it is highly likely that I am being a bit of an idiot and missing something obvious....but... Would really appreciate any help from anyone...
Many thanks in advance
This query will do the job, and for all TYPE
SELECT
Description, [CAR], [CAT], [MAT], [EAT], [PAR], [MAR], [FAR], [MOT], [LOT], [COT], [ROT]
FROM
(SELECT
unpvt.TYPE
,unpvt.Description
,unpvt.value
FROM (
SELECT
t.TYPE
,CONVERT(sql_variant,MAX(maxResult.MAX_RESULT)) as MAX_RESULT
,CONVERT(sql_variant,MIN(minResult.MIN_RESULT)) as MIN_RESULT
,CONVERT(sql_variant,MAX(CASE WHEN maxResult.MAX_RESULT IS NOT NULL THEN t.DATE ELSE NULL END)) as MAX_DATE
,CONVERT(sql_variant,MIN(CASE WHEN minResult.MIN_RESULT IS NOT NULL THEN t.DATE ELSE NULL END)) as MIN_DATE
FROM
table_name t -- You need to set your table name
LEFT JOIN (SELECT
TYPE
,MIN(RESULT) as MIN_RESULT
FROM
table_name -- You need to set your table name
GROUP BY
TYPE) minResult
on minResult.TYPE = t.TYPE
and minResult.MIN_RESULT = t.RESULT
LEFT JOIN (SELECT
TYPE
,MAX(RESULT) as MAX_RESULT
FROM
table_name -- You need to set your table name
GROUP BY
TYPE) maxResult
on maxResult.TYPE = t.TYPE
and maxResult.MAX_RESULT = t.RESULT
GROUP BY
t.TYPE) U
unpivot (
value
for Description in (MAX_RESULT, MIN_RESULT, MAX_DATE, MIN_DATE)
) unpvt) P
PIVOT
(
MAX(value)
FOR TYPE IN ([CAR], [CAT], [MAT], [EAT], [PAR], [MAR], [FAR], [MOT], [LOT], [COT], [ROT])
)AS PVT
DEMO : SQLFIDDLE
CONVERT(sql_variant, is a cast for columns to a common data type. This is a requirement of the UNPIVOT operator when you are running with subquery FROM.
It is possible to use the PIVOT command if your SQLServer is 2005 or better, but the raw data for the pivot need to be in a specific format, and the query I came up with is ugly
WITH minmax AS (
SELECT TYPE, RESULT, [date]
, row_number() OVER (partition BY TYPE ORDER BY TYPE, RESULT) a
, row_number() OVER (partition BY TYPE ORDER BY TYPE, RESULT DESC) d
FROM t)
SELECT info
, cam = CASE charindex('date', info)
WHEN 0 THEN cast(cast(cam AS int) AS varchar(50))
ELSE cast(cam AS varchar(50))
END
, car = CASE charindex('date', info)
WHEN 0 THEN cast(cast(car AS int) AS varchar(50))
ELSE cast(cam AS varchar(50))
END
, cat = CASE charindex('date', info)
WHEN 0 THEN cast(cast(cat AS int) AS varchar(50))
ELSE cast(cam AS varchar(50))
END
FROM (SELECT TYPE, 'maxres' info, RESULT value FROM minmax WHERE 1 = d
UNION ALL
SELECT TYPE, 'minres' info, RESULT value FROM minmax WHERE 1 = a
UNION ALL
SELECT TYPE, 'maxdate' info , [date] value FROM minmax WHERE 1 = d
UNION ALL
SELECT TYPE, 'mindate' info , [date] value FROM minmax WHERE 1 = a) DATA
PIVOT
(max(value) FOR TYPE IN ([CAM], [CAR], [CAT])) pvt
It's only a proof of concept so in SQLFiddle I have used a reducet set of fake data (3 row per 3 Type)
After the data preparation
SELECT TYPE, 'maxres' info, RESULT value FROM minmax WHERE 1 = d
UNION ALL
SELECT TYPE, 'minres' info, RESULT value FROM minmax WHERE 1 = a
UNION ALL
SELECT TYPE, 'maxdate' info , [date] value FROM minmax WHERE 1 = d
UNION ALL
SELECT TYPE, 'mindate' info , [date] value FROM minmax WHERE 1 = a
the value column is implicitly casted to the more complex datatype, in this case DateTime (you cannot have different data type in the same column), to see the data in the intended way an explicit cast is in needed, and is done with the CASE and CAST in
, cam = CASE charindex('date', info)
WHEN 0 THEN cast(cast(cam AS int) AS varchar(50))
ELSE cast(cam AS varchar(50))
END
the CASE check the data type, looking for the substring 'date' in the info column, then cast the row value back to INT for the minres and maxres column and in any case cast the value to varchar(50) to have the same data type again
UPDATE
With the sql_variant the CASE CAST block is not needed, thanks Ryx5
WITH minmax AS (
SELECT TYPE, RESULT, [date]
, row_number() OVER (partition BY TYPE ORDER BY TYPE, RESULT) a
, row_number() OVER (partition BY TYPE ORDER BY TYPE, RESULT DESC) d
FROM table_name)
SELECT info
, [CAM], [CAR], [CAT]
FROM (SELECT TYPE, 'maxres' info, cast(RESULT as sql_variant) value
FROM minmax WHERE 1 = d
UNION ALL
SELECT TYPE, 'minres' info, cast(RESULT as sql_variant) value
FROM minmax WHERE 1 = a
UNION ALL
SELECT TYPE, 'maxdate' info , cast([date] as sql_variant) value
FROM minmax WHERE 1 = d
UNION ALL
SELECT TYPE, 'mindate' info , cast([date] as sql_variant) value
FROM minmax WHERE 1 = a) DATA
PIVOT
(max(value) FOR TYPE IN ([CAM], [CAR], [CAT])) pvt