Extract array of JSONs to columns in SQL - sql

I have the following table with JSON collections:
ID
SliderJson
1
[{"Slider":11, "Value":2},{"Slider":4, "Value":3}]
2
3
[{"Slider":11, "Value":4},{"Slider":4, "Value":3},{"Slider":25, "Value":3},{"Slider":2, "Value":4},{"Slider":5, "Value":3}]
As can be see in the example not all records have a value, and those that have the length of the array vary (by a maximum of 9 items).
Ideally I would like to create a column for each slider that contains its entry value, but there are about 400 million records and about 80 different sliders.
So I would be happy to create a columns only for certain sliders, say 4 and 5 and get the following table.
ID
SliderJson
4
5
1
[{"Slider":11, "Value":2},{"Slider":4, "Value":3}]
3
NULL
2
NULL
NULL
3
[{"Slider":11, "Value":4},{"Slider":4, "Value":3},{"Slider":25, "Value":3},{"Slider":2, "Value":4},{"Slider":5, "Value":3}]
3
3
Or alternatively create a table that will extract the json to the columns in the following way:
ID
SliderJson
slider1
value1
slider2
value2
slider3
value3
1
[{"Slider":11, "Value":2},{"Slider":4, "Value":3}]
11
2
4
3
NULL
NULL
2
NULL
NULL
NULL
NULL
NULL
NULL
3
[{"Slider":11, "Value":4},{"Slider":4, "Value":3},{"Slider":25, "Value":3},{"Slider":2, "Value":4},{"Slider":5, "Value":3}]
11
4
4
3
25
3
Both options are good and working for me, the only consideration is efficiency because as mentioned there are a millions of records (and maybe there are other options that are preferred and I have not thought about).
It also important that each record be associated with its original id.
So far I tried the following proceeder, however even when I execute it on very small amount of rows (only 100) it took hours, so I guess something wrong.
DECLARE #NOTE_ID uniqueidentifier
DECLARE #USER_ID uniqueidentifier
DECLARE #SINGEL_SLIDER NVARCHAR(MAX)
DECLARE SLIDER_CURSOR CURSOR FOR SELECT [NoteID],[UserID],[SliderJSON] FROM [dbo].[SmallData]
OPEN SLIDER_CURSOR
FETCH NEXT FROM SLIDER_CURSOR INTO #NOTE_ID, #USER_ID, #SINGEL_SLIDER
WHILE ##FETCH_STATUS = 0
BEGIN
IF len(#SINGEL_SLIDER)>1
BEGIN
IF OBJECT_ID('tempdb..#TMP') IS NOT NULL
DROP TABLE #TMP
SELECT *
INTO #TMP
FROM OPENJSON(#SINGEL_SLIDER)
DECLARE #SLIDER_VALUE NVARCHAR(MAX)
DECLARE SLIDER_VALUE_CURSOR CURSOR FOR SELECT [value] FROM #TMP
OPEN SLIDER_VALUE_CURSOR
FETCH NEXT FROM SLIDER_VALUE_CURSOR INTO #SLIDER_VALUE
WHILE ##FETCH_STATUS = 0
BEGIN
IF OBJECT_ID('tempdb..#TMP1') IS NOT NULL
DROP TABLE #TMP1
SELECT *
INTO #TMP1
FROM OPENJSON(#SLIDER_VALUE)
DECLARE #SLIDER_ID NVARCHAR(100)
DECLARE #SLIDER_OPTION_ID NVARCHAR(100)
SET #SLIDER_ID = (SELECT [value] FROM #TMP1 WHERE [key] = 'Slider')
SET #SLIDER_OPTION_ID = (SELECT [value] FROM #TMP1 WHERE [key] = 'Value')
IF #SLIDER_ID = 4
BEGIN
UPDATE [dbo].[SmallData]
SET [4] = #SLIDER_OPTION_ID
WHERE [NoteID] = #NOTE_ID
END
ELSE IF #SLIDER_ID = 7
BEGIN
UPDATE [dbo].[SmallData]
SET [7] = #SLIDER_OPTION_ID
WHERE [NoteID] = #NOTE_ID
END
ELSE IF #SLIDER_ID = 1
BEGIN
UPDATE [dbo].[SmallData]
SET [1] = #SLIDER_OPTION_ID
WHERE [NoteID] = #NOTE_ID
END
ELSE IF #SLIDER_ID = 10
BEGIN
UPDATE [dbo].[SmallData]
SET [10] = #SLIDER_OPTION_ID
WHERE [NoteID] = #NOTE_ID
END
ELSE IF #SLIDER_ID = 43
BEGIN
UPDATE [dbo].[SmallData]
SET [43] = #SLIDER_OPTION_ID
WHERE [NoteID] = #NOTE_ID
END
ELSE IF #SLIDER_ID = 15
BEGIN
UPDATE [dbo].[SmallData]
SET [15] = #SLIDER_OPTION_ID
WHERE [NoteID] = #NOTE_ID
END
ELSE IF #SLIDER_ID = 18
BEGIN
UPDATE [dbo].[SmallData]
SET [18] = #SLIDER_OPTION_ID
WHERE [NoteID] = #NOTE_ID
END
END
FETCH NEXT FROM SLIDER_VALUE_CURSOR INTO #SLIDER_VALUE
END
CLOSE SLIDER_VALUE_CURSOR
DEALLOCATE SLIDER_VALUE_CURSOR
FETCH NEXT FROM SLIDER_CURSOR INTO #NOTE_ID, #USER_ID, #SINGEL_SLIDER
END
CLOSE SLIDER_CURSOR
DEALLOCATE SLIDER_CURSOR
I would appreciate any help on this subject.

I'm unsure why you thought you needed all those cursors and a temp table, they are unnecessary.
You need two OPENJSONs here. To get just the value for each slider, you can just pivot on the slider number.
SELECT
s.*,
j.*
FROM dbo.SmallData s
CROSS APPLY (
SELECT
pvt.*
FROM (
SELECT
j2.Slider,
j2.Value
FROM OPENJSON (s.SliderJSON) j1
CROSS APPLY OPENJSON (j1.value)
WITH (Slider int, Value int) j2
) j
PIVOT (
MIN(Value) FOR Slider IN
([4],[5])
) pvt
) j;
Your second version can also be done pretty simply with a multi-column pivot.
SELECT
s.*,
j.*
FROM dbo.SmallData s
CROSS APPLY (
SELECT
MAX(CASE WHEN j1.[key] = '0' THEN j2.Slider END) slider1,
MAX(CASE WHEN j1.[key] = '0' THEN j2.Value END) value1,
MAX(CASE WHEN j1.[key] = '1' THEN j2.Slider END) slider2,
MAX(CASE WHEN j1.[key] = '1' THEN j2.Value END) value2,
MAX(CASE WHEN j1.[key] = '2' THEN j2.Slider END) slider3,
MAX(CASE WHEN j1.[key] = '2' THEN j2.Value END) value3,
MAX(CASE WHEN j1.[key] = '3' THEN j2.Slider END) slider4,
MAX(CASE WHEN j1.[key] = '3' THEN j2.Value END) value4,
MAX(CASE WHEN j1.[key] = '4' THEN j2.Slider END) slider5,
MAX(CASE WHEN j1.[key] = '4' THEN j2.Value END) value5,
MAX(CASE WHEN j1.[key] = '5' THEN j2.Slider END) slider6,
MAX(CASE WHEN j1.[key] = '5' THEN j2.Value END) value6,
MAX(CASE WHEN j1.[key] = '6' THEN j2.Slider END) slider7,
MAX(CASE WHEN j1.[key] = '6' THEN j2.Value END) value7,
MAX(CASE WHEN j1.[key] = '7' THEN j2.Slider END) slider8,
MAX(CASE WHEN j1.[key] = '7' THEN j2.Value END) value8,
MAX(CASE WHEN j1.[key] = '8' THEN j2.Slider END) slider9,
MAX(CASE WHEN j1.[key] = '8' THEN j2.Value END) value9
FROM OPENJSON (s.SliderJSON) j1
CROSS APPLY OPENJSON (j1.value)
WITH (Slider int, Value int) j2
) j;

Related

Aggregate function in update query with case statement in sql server

I am trying to write update query by using aggregate function and case statement.
Some how i am stuck
Initially i have written following query which gave me error tha,"Aggregate function can not be used in update statement
UPDATE report
SET report.LoadDischargeQty =
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'D' AND cargo.CRG_Quantity is NOT NULL THEN cargo.CRG_Quantity
ELSE
CASE WHEN report.PlaId = 'LP' THEN
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'D' THEN ISNULL(SUM(CRG_SFgrMT),0) END -
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'A' THEN ISNULL(SUM(CRG_SFgrMT),0)END
WHEN report.PlaId = 'DP' THEN
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'A' THEN ISNULL(SUM(CRG_SFgrMT),0) END-
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'D' THEN ISNULL(SUM(CRG_SFgrMT),0)END
ELSE 0 END
END
from #CargoPerformanceReport report
INNER JOIN POSCARGO cargo ON cargo.POS_ID = report.PositionId AND ISNULL(cargo.CRG_Deleted,0)=0
So I refactored it as follow
UPDATE report
SET report.LoadDischargeQty =
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'D' AND cargo.CRG_Quantity is NOT NULL THEN cargo.CRG_Quantity
ELSE
select quantity.dischargeQuantity from (SELECT CASE WHEN report.PlaId = 'LP' THEN
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'D' THEN ISNULL(SUM(CRG_SFgrMT),0) END -
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'A' THEN ISNULL(SUM(CRG_SFgrMT),0)END
WHEN report.PlaId = 'DP' THEN
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'A' THEN ISNULL(SUM(CRG_SFgrMT),0) END-
CASE WHEN SUBSTRING(CRG_ArrDep,1,1) = 'D' THEN ISNULL(SUM(CRG_SFgrMT),0)END
ELSE 0 END dischargeQuantity ) quantity
END
from #CargoPerformanceReport report
INNER JOIN POSCARGO cargo ON cargo.POS_ID = report.PositionId AND ISNULL(cargo.CRG_Deleted,0)=0
table structure
CREATE TABLE #CargoPerformanceReport
(
PositionId VARCHAR(12),
PortAndActivityName VARCHAR(100),
PlaId VARCHAR(12),
LoadDischargeQty REAL,
);
Insert into #CargoPerformanceReport
Values('100',null,'LP',null)
CREATE TABLE #Poscargo
(
POS_ID VARCHAR(12),
CRG_ArrDep VARCHAR(3),
CRG_SFgrMT REAL,
CRG_Quantity REAL,
CRG_Deleted BIT
);
Insert Into #Poscargo(POS_ID,CRG_ArrDep,CRG_SFgrMT,null,0)
Values ('100','DD',100)
Insert Into #Poscargo(POS_ID,CRG_ArrDep,CRG_SFgrMT)
Values ('100','AD',100)
Insert Into #Poscargo(POS_ID,CRG_ArrDep,CRG_SFgrMT)
Values ('100','DD',200)
Insert Into #Poscargo(POS_ID,CRG_ArrDep,CRG_SFgrMT)
Values ('100','AD',50)
Insert Into #Poscargo(POS_ID,CRG_ArrDep,CRG_SFgrMT)
Values ('101','DL',200)
Insert Into #Poscargo(POS_ID,CRG_ArrDep,CRG_SFgrMT)
Values ('101','AL',200)
SELECT * FROM #Poscargo
SELECT * FROM #CargoPerformanceReport
result:-
PositionId | PlaId | LoadDischargeQty
100 | LP | 150
but it is not right way and also has error.
anyone have optimized solution for the same?
Put all that stuff into subquery:
SELECT LoadDischargeQty =
CASE
WHEN report.PlaId = 'LP'
THEN 1
ELSE -1
END * cargo.qty
FROM CargoPerformanceReport report
CROSS APPLY(
SELECT SUM(
CASE
WHEN CRG_ArrDep LIKE 'D%'
THEN 1
WHEN CRG_ArrDep LIKE 'A%'
THEN -1
ELSE 0
END * ISNULL(CRG_SFgrMT, 0)
) qty
FROM POSCARGO cargo
WHERE cargo.POS_ID = report.PositionId
AND ISNULL(cargo.CRG_Deleted,0)=0
) cargo
http://sqlfiddle.com/#!18/648d0/7
I don't understand how is CRG_Quantity column supposed to be used and you did not provide any row with that data so I removed it to show you the aggregation itself. Works fine, you'll get your 150. You may easily convert it into update statement.
Perhaps something like this?
It uses cases with summed cases.
Test on SQL Fiddle here
UPDATE t
SET LoadDischargeQty = q.CalcDischargeQty
FROM #CargoPerformanceReport t
JOIN
(
SELECT report.PositionId, report.PlaId,
CASE
WHEN SUM(CASE WHEN LEFT(cargo.CRG_ArrDep,1) = 'D' THEN cargo.CRG_Quantity END) IS NOT NULL
THEN SUM(CASE WHEN LEFT(cargo.CRG_ArrDep,1) = 'D' THEN cargo.CRG_Quantity END)
ELSE CASE
WHEN report.PlaId = 'LP'
THEN SUM(CASE WHEN LEFT(cargo.CRG_ArrDep,1) = 'D' THEN cargo.CRG_SFgrMT END) -
SUM(CASE WHEN LEFT(cargo.CRG_ArrDep,1) = 'A' THEN cargo.CRG_SFgrMT END)
WHEN report.PlaId = 'DP'
THEN SUM(CASE WHEN LEFT(cargo.CRG_ArrDep,1) = 'A' THEN cargo.CRG_SFgrMT END) -
SUM(CASE WHEN LEFT(cargo.CRG_ArrDep,1) = 'D' THEN cargo.CRG_SFgrMT END)
ELSE 0
END
END AS CalcDischargeQty
FROM #CargoPerformanceReport report
INNER JOIN #Poscargo cargo
ON cargo.POS_ID = report.PositionId AND (cargo.CRG_Deleted = 0 OR cargo.CRG_Deleted IS NULL)
GROUP BY report.PositionId, report.PlaId
) q ON t.PositionId = q.PositionId;
Sample Data
IF OBJECT_ID('tempdb..#CargoPerformanceReport') IS NOT NULL DROP TABLE #CargoPerformanceReport;
CREATE TABLE #CargoPerformanceReport
(
PositionId VARCHAR(12) PRIMARY KEY,
PortAndActivityName VARCHAR(100),
PlaId VARCHAR(12),
LoadDischargeQty REAL
);
IF OBJECT_ID('tempdb..#Poscargo') IS NOT NULL DROP TABLE #Poscargo;
CREATE TABLE #Poscargo
(
POS_ID VARCHAR(12),
CRG_ArrDep VARCHAR(3),
CRG_SFgrMT REAL,
CRG_Quantity REAL,
CRG_Deleted BIT
);
Insert into #CargoPerformanceReport Values
('100','name1','LP',null),
('101','name2','DP',null),
('102','name3','DP',null);
Insert Into #Poscargo(POS_ID, CRG_ArrDep, CRG_SFgrMT, CRG_Quantity, CRG_Deleted) Values
('100','DD',100,null,0)
,('100','AD',100,null,0)
,('100','DD',200,null,0)
,('100','AD',50,null,0)
,('101','DL',100,null,0)
,('101','AL',200,null,0)
,('102','DL',100,500,0)
,('102','AL',200,null,0);
Result
PositionId PortAndActivityName PlaId LoadDischargeQty
---------- ------------------- ----- ----------------
100 name1 LP 150
101 name2 DP 100
102 name3 DP 500

"Error" value on name and description creating strange functionality

I got a raw data file with its content looking like this:
MSN_Check,Text,25,MSN check
0,Text,1,(Result)
HWIMPL,Text,10,HWIMPL version reading
007F,Text,6,(Measure)
1,Text,1,(Result)
VHW,Text,10,FMT hardware version
494131383346,Text,10,(Measure)
0,Text,1,(Result)
TOTAL_VER,Text,25,Total version reading
313031303130,Text,6,(Measure)
1,Text,1,(Result)
CAL_MCU,Text,25,Total version reading
05,Text,6,(Measure)
Error,Text,25,Error
9.8499985089315E-07,Numeric,Float 3.3,(Measure)
CAL_EEPROM,Text,25,Total version reading
05,Numeric,Float 3.3,(Measure)
1,Text,1,(Result)
And I needed to extract and store in variables the name, example MSN_Check ,the description, example MSN check its result for example 0 and its measure , for example 007F but in some places I have results only or measures only so just spliting them wouldn't have helped.So my idea was:
First of all I created a template table named dbo.template that looks like this:
Name TestDescription Measure Result ID
----------------------------------------------
MSN_Check MSN check 0 1 1
HWIMPL HWIMPL version reading 1 1 2
VHW FMT hardware version 1 1 3
TOTAL_VER Total version reading 1 1 4
CAL_MCU Total version reading 1 0 5
Error Error 1 0 6
CAL_EEPROM Total version reading 1 1 7
In this table we have the name,description,if_measure(meaning 1 if we have a measure or 0 if we dont) and the if_result.And I made a query looking like this:
DECLARE #crlf AS CHAR(2) = CHAR(13) + CHAR(10)
declare #testname varchar(max),#testDescription varchar(max), #if_measure char(1), #if_result char(1), #row int = '1', #id int
set #LogEntry = (SELECT REPLACE(#LogEntry,#crlf,','))
declare #name varchar(max),#description varchar(MAX), #measure varchar(20), #result char(1)
declare #Output table(OutTestName varchar(max),OUTTestDescription varchar(max), OutMeasure varchar(50), OutResult varchar(50))
declare #maximum int = (select MAX(ID) from dbo.template_FMT)
declare #LogEntry1 as nvarchar(max)
declare #LogEntry2 as nvarchar(max)
while #row <= #maximum
BEGIN
set #name = null
set #description = null
set #measure = null
set #result = null
set #testname = (select Name from dbo.template_FMT where ID = #row)
set #testDescription = (select TestDescription from dbo.template_FMT where ID = #row)
set #if_measure = (select Measure from dbo.template_FMT where ID = #row)
set #if_result = (select Result from dbo.template_FMT where ID = #row)
set #id = (select ID from dbo.Split(#LogEntry, ',') where Data = #testname)
SELECT #LogEntry1 = Name FROM dbo.template_FMT where id = #row
set #name = #LogEntry1
SELECT #LogEntry2 = TestDescription FROM dbo.template_FMT where id = #row
set #description = #LogEntry2
if #if_measure > 0 and #if_result > 0
begin
set #measure = (select Data from dbo.Split(#LogEntry, ',') where ID = #id+4)
set #result = (select Data from dbo.Split(#LogEntry, ',') where ID = #id+8)
insert into #Output (OutTestName, OUTTestDescription, OutMeasure, OutResult) Values(#name,#description, #measure, #result)
end
if #if_measure > 0 and #if_result = 0
begin
set #measure = (select Data from dbo.Split(#LogEntry, ',') where ID = #id+4)
set #result = null
insert into #Output (OutTestName, OUTTestDescription, OutMeasure, OutResult) Values(#name,#description, #measure, #result)
end
if #if_measure = 0 and #if_result > 0
begin
set #measure = null
set #result = (select Data from dbo.Split(#LogEntry, ',') where ID = #id+4)
insert into #Output (OutTestName, OUTTestDescription, OutMeasure, OutResult) Values(#name,#description, #measure, #result)
end
set #row = #row + 1
END
select * from #Output
And it worked! but the only problem I have is where I have the row with the name Error with the description Error,it would return the last remembered value so instead of having
CAL_MCU Total version reading 05 NULL
Error Error 9.8499985089315E-07 NULL
CAL_EEPROM Total version reading 05 1
I get:
CAL_MCU Total version reading 05 NULL
Error Error 05 NULL
CAL_EEPROM Total version reading 05 1
And I would like to store the Error cant find Result with ID into variables if any of you have any suggestions :)
P.S. I think it has something to do with the fact that the name and description have the same name (Error)
I believe that your problem can be solved without the need for while loops and string splitting functions. I recommend using the OPENROWSET function to read your raw data file as a standard table. You can then use standard T-SQL query to format the result into the desired output.
The first step is to ensure that ad-hoc queries is enable on your server this can be accomplished by executing the following command.
sp_configure 'show advanced options', 1;
RECONFIGURE;
GO
sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;
The next step is to define a format file for your text file. This will help SQL Server understand the text file structure when loading the raw data. Based on the supplied sample data your format file should look as follow:
10.0
4
1 SQLCHAR 0 100 "," 1 Col1 SQL_Latin1_General_CP1_CI_AS
2 SQLCHAR 0 100 "," 2 Col2 SQL_Latin1_General_CP1_CI_AS
3 SQLCHAR 0 100 "," 3 Col3 SQL_Latin1_General_CP1_CI_AS
4 SQLCHAR 0 100 "\r\n" 4 Col4 SQL_Latin1_General_CP1_CI_AS
I have uploaded the format file and example raw data file I have used to test the example at the following links:
http://www.filedropper.com/format
http://www.filedropper.com/rawdatafile
The final step is to run the OPENROWSET query to load the file data and transform the data to the desired output. If you are using SQL Server 2008 r2 then the following query should work:
-- 2008 R2 Version
WITH CTE_VariableRawData
AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS ID
,[RawData].Col1 AS [VariableOrMeasure]
,(
CASE [RawData].Col4
WHEN '(Result)' THEN 0
WHEN '(Measure)' THEN 0
ELSE 1
END
) AS IsVariable
,(
CASE [RawData].Col4
WHEN '(Result)' THEN 1
ELSE 0
END
) AS IsResult
,(
CASE [RawData].Col4
WHEN '(Measure)' THEN 1
ELSE 0
END
) AS IsMeasure
,[RawData].Col4 AS [Description]
FROM OPENROWSET(BULK N'C:\temp\raw_data_file.txt', FORMATFILE = 'c:\temp\format.txt') AS [RawData]
)
,
CTE_RawDataByVariableID
AS
(
SELECT ID
,(
SELECT SUM([IsVariable])
FROM CTE_VariableRawData RunningTotal
WHERE RunningTotal.ID <= CTE_VariableRawData.ID
) AS VariableID
,[VariableOrMeasure]
,[IsVariable]
,[IsResult]
,[IsMeasure]
,[Description]
FROM CTE_VariableRawData
)
SELECT VariableID
,MAX(
CASE [IsVariable]
WHEN 1 THEN [VariableOrMeasure]
ELSE NULL
END
) AS [Variable]
,MAX(
CASE [IsVariable]
WHEN 1 THEN [Description]
ELSE NULL
END
) AS [Description]
,MAX(
CASE [IsMeasure]
WHEN 1 THEN [VariableOrMeasure]
ELSE NULL
END
) AS [Measure]
,MAX(
CASE [IsResult]
WHEN 1 THEN [VariableOrMeasure]
ELSE NULL
END
) AS [Result]
FROM CTE_RawDataByVariableID
GROUP BY VariableID
ORDER BY VariableID
If you are using SQL Server 2012 or later then the following query will be a bit more optimal:
WITH CTE_VariableRawData
AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS ID
,[RawData].Col1 AS [VariableOrMeasure]
,(
CASE [RawData].Col4
WHEN '(Result)' THEN 0
WHEN '(Measure)' THEN 0
ELSE 1
END
) AS IsVariable
,(
CASE [RawData].Col4
WHEN '(Result)' THEN 1
ELSE 0
END
) AS IsResult
,(
CASE [RawData].Col4
WHEN '(Measure)' THEN 1
ELSE 0
END
) AS IsMeasure
,[RawData].Col4 AS [Description]
FROM OPENROWSET(BULK N'C:\temp\raw_data_file.txt', FORMATFILE = 'c:\temp\format.txt') AS [RawData]
)
,
CTE_RawDataByVariableID
AS
(
SELECT ID
,SUM([IsVariable]) OVER (ORDER BY ID) AS VariableID
,[VariableOrMeasure]
,[IsVariable]
,[IsResult]
,[IsMeasure]
,[Description]
FROM CTE_VariableRawData
)
SELECT VariableID
,MAX(
CASE [IsVariable]
WHEN 1 THEN [VariableOrMeasure]
ELSE NULL
END
) AS [Variable]
,MAX(
CASE [IsVariable]
WHEN 1 THEN [Description]
ELSE NULL
END
) AS [Description]
,MAX(
CASE [IsMeasure]
WHEN 1 THEN [VariableOrMeasure]
ELSE NULL
END
) AS [Measure]
,MAX(
CASE [IsResult]
WHEN 1 THEN [VariableOrMeasure]
ELSE NULL
END
) AS [Result]
FROM CTE_RawDataByVariableID
GROUP BY VariableID
ORDER BY VariableID;
Note that in both queries you will have to change the location of your raw data file and format file to the desired location within the OPENROWSET(BULK N'C:\temp\raw_data_file.txt', FORMATFILE = 'c:\temp\format.txt') call.

How to select on stored procedure with filter have more than 3 value

I would like to know that how to select when using stored procedure with filter as combobox in website have more than 3 value
Exp: I would like to select match listing. and filter is "IsFinish" with value (All, Yes, No)
DECLARE #IsFinish INT -- 1: All 2: Yes 3: No
SELECT * FROM MATCH
WHERE [Status] = ?
Status values: F: Finished C: Canceled L: Live N: Non-Live P:Pause X:(Close) Waiting Confirm
When select All the result will return all status.
When select Yes the result will return F & X.
When select No the result will return N, L, C, P.
I would like filter them by once select.
How can I do it?
Prepare Data
CREATE TABLE [Match] ([Status] CHAR(1) PRIMARY KEY, [Wording] VARCHAR(50));
INSERT INTO [Match] ([Status], [Wording]) VALUES
('F', 'Finished'),
('C', 'Canceled'),
('L', 'Live'),
('N', 'Non-Live'),
('P', 'Pause'),
('X', '(Close) Waiting Confirm');
Prepare Procedure
CREATE PROCEDURE [FilterMatch] (#IsFinish INT = 1 /* 1: All (Default) 2: Yes 3: No */)
AS
SELECT * FROM [Match]
WHERE #IsFinish = 1 OR
(#IsFinish = 2 AND [Status] In ('F','X')) OR
(#IsFinish = 3 AND [Status] In ('N','L','C','P'));
Run
Exec FilterMatch;
Exec FilterMatch 2;
Exec FilterMatch #IsFinish = 3;
In SQL-Server you can achieve It in following:
where [status] LIKE (case #IsFinish when 1 then '%' end) or
[status] = (case #IsFinish when 2 then 'F' end) or
[status] = (case #IsFinish when 2 then 'X' end) or
[status] = (case #IsFinish when 3 then 'N' end) or
[status] = (case #IsFinish when 3 then 'L' end) or
[status] = (case #IsFinish when 3 then 'C' end) or
[status] = (case #IsFinish when 3 then 'P' end)
Use IN and CASE and OR. Something like:
WHERE isFinish = 1
OR isFinish = 2 AND Status IN ('F','X')
OR isFinish = 3 AND Status IN ('N','L','C','P')
I have tried to using where case when with
where case when [status] IN ('L','N','F','X','C','P') then 0
when [status] in ('F','X') THEN 1
when [Status] IN ('L','N','C','P') THEN 2 END = #IsFinish
But I'm not feeling It look good.
I look forward to hearing from you in the nearest time.

SQL Conversion failed when converting row number

So I've been trying to add an Dynamic Row Number column with out using Dynamic SQL. However when I try I get an error 'Conversion failed when converting character string to smalldatetime data type.'
I Know the Error is coming from in the functions So if you want to just look at the switch case in the function that is the problem, but here is the stored procedure just in case you need to see it.
I have a store procedure which looks like this:
ALTER PROCEDURE [dbo].[MMS_EdgateMainQueue]
-- Add the parameters for the stored procedure here
#OrderByColumnID int = 3,
#Skip int = 0,
#Take int = 0,
#Descending bit = 1,
#ResultCount INT OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #UrlTitlePrefix varchar(2080) = '<a href="/Title/PageByExtTitleID?ActionName=Edgate&ExtTitleID='
Declare #UrlProducerPrefix varchar(2080) = '<a href="/Producers/ByExtVendorID?ActionName=Details&ExtVendorID='
Declare #Urlmidfix varchar(100) = '">'
Declare #UrlPostFix varchar(100) = '</a>'
SELECT TOP (#Take)
[row_numb],
#UrlTitlePrefix + ExtTitleID + #Urlmidfix + ExtTitleID + #UrlPostFix as [Item #],
f.Title as Name,
#UrlProducerPrefix + f.ExtVendorID + #Urlmidfix + f.DisplayName + #UrlPostFix as Producer,
f.Created as Created,
isnull(f.Academic, '') as Academic,
isnull(f.Sears,'') as Sears,
isnull(f.Editor, '') as Editor,
CONVERT(INT, f.[Copy]) AS Copy,
f.[Segment],
CONVERT(INT, f.[Taxonomy]) AS Taxonomy,
f.[Priority]
FROM EdgateNewTitlesInnerQuery(#OrderByColumnID, #Descending) as f
Where f.[row_numb] Between ((#Skip * #Take) + 1) and ((#Skip + 1) * #Take) order by f.[row_numb]
END
And The Inner Function Looks Like:
ALTER FUNCTION [dbo].[EdgateNewTitlesInnerQuery]
(
#OrderByColumnID int,
#Descending bit
)
RETURNS TABLE
AS
RETURN
(
SELECT DISTINCT
v.ExtVendorID,
t.ID,
t.ExtTitleID,
t.Title,
v.DisplayName,
t.Created,
ecs.Title as [Academic],
ssub.Title as [Sears],
etw.EditorName as [Editor],
etw.CopyDone AS [Copy],
etw.SegmentsStatus as [Segment],
etw.TaxonomyDone AS [Taxonomy],
CASE WHEN wft.[Priority] is null THEN 0 ELSE wft.[Priority] END as [Priority],
--row_number() OVER (ORDER BY t.Created DESC) AS [row_number]
row_number() OVER (ORDER BY
CASE #OrderByColumnID WHEN 0 THEN t.ExtTitleID
WHEN 1 THEN t.Title
WHEN 2 THEN v.DisplayName
WHEN 3 THEN t.Created
WHEN 4 THEN ecs.Title
WHEN 5 THEN ssub.Title
WHEN 6 THEN etw.EditorName
WHEN 7 THEN etw.CopyDone
WHEN 8 THEN etw.SegmentsStatus
WHEN 9 THEN etw.TaxonomyDone
WHEN 10 THEN CASE WHEN wft.[Priority] is null THEN 0 ELSE wft.[Priority] END
ELSE t.Created
END DESC ) AS [row_numb]
FROM [Title] t
join EdgateTitleWorkflow etw on etw.FK_TitleID = t.ID
join Vendor v on v.ExtVendorID = t.ProducerID
join CollectionItem i on i.TitleID = t.ID and i.CollectionID = 16
left join [EdgateSuggestedAcademicSubject] esas on esas.FK_TitleID = t.ID and esas.isPrimary = 1
left join EC_Subject ecs on ecs.ID = esas.FK_SubjectID
left join [FMGSuggestedSears] fss on fss.FK_TitleID = t.ID and fss.isPrimary = 1
left join [FMGSearsSubjects] ssub on ssub.ID = fss.SearsSubjectID and ssub.ParentID is null
left join [WorkFlow_Tracker] wft on wft.TitleID = t.ID
where (etw.CopyDone = 0 or etw.TaxonomyDone = 0 or etw.SegmentsStatus = 0)
)
I've tried passing this in as a string originally but it just didn't sort at all. So I was looking at similar problems and tried this solution Here
but my switch Case is now throwing a Conversion Error. Does anyone have an Idea on how to fix this?
The problem is that case is an expression that returns one type, defined during compilation. You can fix this with a separate case for each key. I think this is the statement you want:
row_number() OVER (ORDER BY (CASE WHEN #OrderByColumnID = 0 THEN t.ExtTitleID END),
(CASE WHEN #OrderByColumnID = 1 THEN t.Title END),
(CASE WHEN #OrderByColumnID = 2 THEN v.DisplayName END),
(CASE WHEN #OrderByColumnID = 3 THEN t.Created END),
(CASE WHEN #OrderByColumnID = 4 THEN ecs.Title END),
(CASE WHEN #OrderByColumnID = 5 THEN ssub.Title END),
(CASE WHEN #OrderByColumnID = 6 THEN etw.EditorName END),
(CASE WHEN #OrderByColumnID = 7 THEN etw.CopyDone END),
(CASE WHEN #OrderByColumnID = 8 THEN etw.SegmentsStatus END),
(CASE WHEN #OrderByColumnID = 9 THEN etw.TaxonomyDone END),
(CASE WHEN #OrderByColumnID = 10 THEN COALESCE(wft.[Priority], 0) END)
t.Created DESC
)

How to Convert Centesimal to Sexagesimal

I have this query: I need convert the centesimal value from the database to sexagesimal (minutes)
SELECT
DISTINCT RD_MAT,
SUM(CASE WHEN RD_PD IN ('421') THEN RD_HORAS ELSE 0 END) AS 'ATRASOS',
SUM(CASE WHEN RD_PD IN ('420') THEN RD_HORAS ELSE 0 END) AS 'FALTAS',
SUM(CASE WHEN RD_PD IN ('084') THEN RD_HORAS ELSE 0 END) AS 'H.EXTRA 100%',
SUM(CASE WHEN RD_PD IN ('080') THEN RD_HORAS ELSE 0 END) AS 'H.EXTRA 50% ',
SUM(CASE WHEN RD_PD IN ('082') THEN RD_HORAS ELSE 0 END) AS 'H.EXTRA NOTURNA'
FROM SRD020
INNER JOIN SRV020 ON RD_PD = RV_COD
AND SRV020.D_E_L_E_T_ <> '*'
AND SRD020.D_E_L_E_T_ <> '*'
AND RD_MAT = '000123'
WHERE LEFT(RD_DATPGT,6) = '201304'
GROUP BY RD_MAT
The return of H.EXTRA 100% in centesimal is 16:53. But in minutes is 16:49.
Example: 40 + 40 = 80 in centesimal. 40 + 40 = 1:20 in sexagesimal. I need this value.
So, it looks like you're going for something like this. I'm casting to VARCHAR for output purposes, which you of course do not have to do.
DECLARE #value1 INT, #value2 INT
SET #value1 = 40
SET #value2 = 50
SELECT CAST(FLOOR((#value1+#value2)/60) AS VARCHAR(50)) + ':' + CAST((#value1+#value2)%60 AS VARCHAR(50))
Declare #h Varchar(5)='16:53'
Select Cast(DateAdd(SS,CAST(REPLACE(#h,':','.') as Float)*60,0) as Time)
>>> 00:16:31.0000000