SQL Conversion failed when converting row number - sql

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
)

Related

Extract array of JSONs to columns in 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;

How to get columns names that been updated

Suppose I have a table like this :
Table 1:
date account name type status open_account_date
31.12.14 1000 20 40 50 31.12.14
2.1.15 1000 10 10 50 31.12.14
3.1.15 1000 5 15 50 31.12.14
and I want to build a summary table like this for the first quarter :
account numOfChanges Changes
1000 4 (name, type)
The first row in table 1 indicats that that the account was opened and somebody enterd for the account some details but the others indicats changes but i want to know which fields has been changed. Is there any suggestion or an idea how to perform this?
DECLARE #StartOfQuarter DATE = '1/1/2015'
;WITH cteRcordStateBeforeQuarter AS (
SELECT
[date]
,account
,name
,[type]
,[status]
,open_account_date
,RowNum = ROW_NUMBER() OVER (PARTITION BY account ORDER BY [date] DESC)
FROM
#Table
WHERE
[date] < #StartOfQuarter
)
, cteRecordStatesDuringQuarter AS (
SELECT
[date]
,account
,name
,[type]
,[status]
,open_account_date
,RowNum = ROW_NUMBER() OVER (PARTITION BY account ORDER BY [date] ASC) + 1
--add 1 because the first row is going to be the last one prior to quarter
,LatestChangeRowNum = ROW_NUMBER() OVER (PARTITION BY account ORDER BY [date] DESC)
FROM
#Table
WHERE
DATEPART(QQ,[date]) = 1
--change to suite ongoing needs such as quater and YEAR([date]) = ??
)
, cteRecursive AS (
SELECT
[date]
,account
,name
,[type]
,[status]
,open_account_date
,RowNum
,LatestChangeRowNum = 0
,NumOfChanges = 0
,[Changes] = CAST('' AS VARCHAR(100))
FROM
cteRcordStateBeforeQuarter
WHERE
RowNum = 1
UNION ALL
SELECT
q.[date]
,q.account
,q.name
,q.[type]
,q.[status]
,q.open_account_date
,q.RowNum
,LatestChangeRowNum = CAST(q.LatestChangeRowNum AS INT)
,NumOfChanges = r.NumOfChanges
+ CASE WHEN ISNULL(q.name,-99999) <> ISNULL(r.name,-99999) THEN 1 ELSE 0 END
+ CASE WHEN ISNULL(q.[type],-99999) <> ISNULL(r.[type],-99999) THEN 1 ELSE 0 END
+ CASE WHEN ISNULL(q.[status],-99999) <> ISNULL(r.[status],-99999) THEN 1 ELSE 0 END
+ CASE WHEN ISNULL(q.open_account_date,'1/1/1900') <> ISNULL(r.open_account_date,'1/1/1900') THEN 1 ELSE 0 END
,[Changes] = CAST(ISNULL(r.[Changes],'')
+ CASE WHEN ISNULL(q.name,-99999) <> ISNULL(r.name,-99999) AND r.[Changes] NOT LIKE '%name%' THEN ',name' ELSE '' END
+ CASE WHEN ISNULL(q.[type],-99999) <> ISNULL(r.[type],-99999) AND r.[Changes] NOT LIKE '%type%' THEN ',type' ELSE '' END
+ CASE WHEN ISNULL(q.[status],-99999) <> ISNULL(r.[status],-99999) AND r.[Changes] NOT LIKE '%status%' THEN ',status' ELSE '' END
+ CASE WHEN ISNULL(q.open_account_date,'1/1/1900') <> ISNULL(r.open_account_date,'1/1/1900') AND r.[Changes] NOT LIKE '%open_account_date%' THEN ',open_account_date' ELSE '' END
AS VARCHAR(100))
FROM
cteRecordStatesDuringQuarter q
INNER JOIN cteRecursive r
ON q.account = r.account
AND q.RowNum = r.RowNum + 1
)
SELECT
account
,NumOfChanges
,[Changes] = REPLACE(IIF(CHARINDEX(',',[Changes]) = 1, RIGHT([Changes],LEN([Changes]) - 1),[Changes]),',',', ')
FROM
cteRecursive
WHERE
LatestChangeRowNum = 1
If you where using SQL 2012 + it would be a little easier because you could use LAG or LEAD window functions and IIF instead of case. But a recursive cte works pretty well too. I assume your recordset will have multiple accounts as well as multiple quarters and there for multiple recordstates prior to the quarter. Due to this you will need to tweak the date logic slightly but this will give you the gist.
First find the record state prior to the quarter. Then find all of the changes during the quarter. Add some row numbers to determine which is the first and which is the last change. Then use a recursive cte to test for changes. In the end you just need to format the string the way you want.

SQL: LEFT OUTER JOIN not returning any rows

I have a query that is using a LEFT OUTER JOIN to merge 2 data sets. I know both data sets should return data because I ran the superquery and the subquery separately. For some reason, the query is returning zero results. Anyone know why?
Left data:
item FG_lots
447845 E2211
Right data:
candy_lot_check candy_item
L2211 835116
Intended result:
item FG_lots candy_lot_check candy_item
447845 E2211 null null
The result from my broken query (no results):
item FG_lots candy_lot_check candy_item
The query:
--Initialization--
DECLARE #Item NVARCHAR(30) = '447845'
DECLARE #Date datetime = '6/13/2016'
SET DATEFIRST 1;
DECLARE #client NVARCHAR(20)
SET #client = (SELECT i.Uf_ClientName FROM item AS i WHERE i.item = #Item)
DECLARE #count integer
--Query--
SET #count = (CASE
WHEN (#client = 'A' OR #client = 'B')
THEN 4
WHEN #client = 'C'
THEN 3
WHEN #client = 'D'
THEN 5
ELSE
4
END)
SELECT DISTINCT
t.item,
LEFT(t.lot,#count) AS FG_lots,
(CASE
WHEN candylot.candy_lots IS NULL
THEN 'NO MATCH'
ELSE candylot.candy_lots
END) AS candy_lot_check,
(CASE
WHEN candylot.item IS NULL
THEN 'NO MATCH'
ELSE candylot.item
END) AS candy_item
FROM
ISW_LPTrans AS t
LEFT OUTER JOIN
(
SELECT
t.item,
LEFT(t.lot,#count) AS candy_lots,
t.ref_num AS job,
t.ref_line_suf AS suffix
FROM
ISW_LPTrans AS t
INNER JOIN item AS i on i.item = t.item
WHERE
i.product_code = 'RM-Candy' AND
t.trans_date = #Date AND
t.trans_type = 'I' AND
t.ref_num IN
(
SELECT TOP 1
j.job
FROM
job AS j
WHERE
j.item = #Item AND
j.job_date = (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, #Date), #Date))
ORDER BY
j.job
)
AND t.ref_line_suf IN
(
SELECT TOP 1
j.suffix
FROM
job AS j
WHERE
j.item = #Item AND
j.job_date = (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, #Date), #Date))
)
GROUP BY
t.item,
t.lot,
t.ref_num,
t.ref_line_suf
) AS candylot ON LEFT(t.lot, #count) = candylot.candy_lots
WHERE
t.ref_num = candylot.job AND
t.ref_line_suf = candylot.suffix AND
t.trans_type = 'F' AND
t.item = #Item AND
t.trans_date = #Date
You've got two 't' aliases, try altering it.
It seems you could rewrite it to make it more readable (joinwise, not indentwise), it could be that something's not right in the logic as well

tsql arithmetic overflow converting expression to data type int only with adodb

with the application I am working on I get this error:
error '80040e57'
Arithmetic overflow error converting expression to data type int
when this query:
SELECT 0 as type_elm
, 999 AS key0
, def_car.desc_elm as sh_elm
, def_car.desc_elm
, id_prd = CAST((CASE WHEN def_key0.key0 IS NULL AND def_car.desc_elm <> 'Non Perfezionati'
THEN CAST((-100 * def_ger.id_prd) as bigint) ELSE (-100 * def_ger.id_cld) + (ISNULL(def_key0.key0,9) * 10) END) AS BIGINT)
, id_cld = CAST((CASE WHEN def_ger.id_cld > 0 THEN CAST((-100 * def_ger.id_cld) as bigint) ELSE 0 END ) AS BIGINT)
,CAST(0 AS BIGINT) as id_prd_real
,CAST(0 AS BIGINT) as cessato_area
, cessato = CAST((CASE WHEN def_ger.id_cld = 0 THEN def_ger.id_prd ELSE 100 - (def_key0.key0 * 10) END) AS BIGINT)
,cessato_orig = CAST((CASE WHEN def_ger.id_cld = 0 THEN def_ger.id_prd ELSE 0 END) AS BIGINT) FROM def_car
INNER JOIN def_ger ON def_car.id_prd = def_ger.id_prd
LEFT JOIN def_key0 ON def_key0.desc_key0 = def_car.desc_elm
WHERE (def_ger.key0 = 999)
AND def_ger.key_ndg = 539
AND (def_ger.id_cld = 0 OR def_car.id_prd > 890000000)
AND def_car.desc_elm <> 'Cestino'
UNION SELECT def_tree.type_elm
, 999 as key0
, def_tree.sh_elm
, def_tree.desc_elm
, id_prd = CAST((CASE WHEN def_tree.id_prd > 800000000 THEN def_tree.id_prd
ELSE CAST(CAST(def_car.id_prd as varchar) + RIGHT(('0000' + CAST(def_tree.id_prd as varchar)), 4) as bigint ) END) AS BIGINT)
, id_cld = CAST((CASE WHEN def_tree.id_cld > 800000000 THEN def_tree.id_cld WHEN def_tree.id_cld <= 0 THEN (-100 * def_ger.id_cld) + (def_tree.key0 * 10)
ELSE CAST(CAST(def_car.id_prd as varchar) + RIGHT(('0000' + CAST(def_tree.id_cld as varchar)), 4) as bigint ) END ) AS BIGINT)
, id_prd_real = CAST((CASE WHEN def_tree.id_prd > 0 THEN def_tree.id_prd ELSE def_car.id_prd END ) AS BIGINT)
,CAST(def_car.id_prd AS BIGINT) as cessato_area
, CAST(0 AS BIGINT) as cessato
, CAST(0 AS BIGINT) as cessato_orig FROM def_tree LEFT JOIN def_key0 ON def_tree.key0 = def_key0.key0 LEFT JOIN def_car ON def_key0.desc_key0 = def_car.desc_elm
LEFT JOIN def_ger ON def_ger.id_prd = def_car.id_prd WHERE def_ger.key_ndg = 539 ORDER BY cessato DESC
, id_cld
, type_elm DESC
, desc_elm
is executed in an asp Application with an adoDb object, the wierd think is that this query is executed without problems in SQL Server and after executed into SQL Server the application runs without erro until I clear the cache of SQL Server.I do not understand this issue.
The reason you get the error from ADO but not SSMS is different execution plans. One plan likely evaluates the expression with the problem value earlier in the plan.
Consider changing expressions like this from:
CAST((-100 * def_ger.id_cld) as bigint)
to
CAST(-100 * CAST(def_ger.id_cld as bigint))
so that the intermediate result as well as the final result is the larger type.

Execution of sql query takes a long time

I have this problem with my query that it is really slow. I am using MSSQL server 2008 and have 3 DB with hundreds of sample data in it. The query will return a name and value and a computed percentage based on the 3 DBs. But the query I have will take almost 10mins to execute which is really a long time to take. I am still learning SQL and still not that good so I think the query I have is not using the best practice and not organized. Can anybody point to me where or how I can improve my query to run faster?
SELECT data.Ret,
case
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') and (data.rowid % 50) = 0 then (data.rowid / 50)-1
when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5') then (data.rowid / 50)
else 0 end as batchStore
,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal,data.Version
,data.A_Percent,data.T_Percent,data.F_Percent
from
(
SELECT report.Ret,
CASE when #group_by= 'site' OR (#group_by='attribute' AND #attribute_id = '5')
then row_number() over (PARTITION BY report.Ret,report.Version order by report.Ret, report.MajorName)
else 0 end as rowid
,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal,report.Version
,report.GTotal_A,report.GTotal_T,report.GTotal_F
,ISNULL(sum(report.Abn) / NULLIF(cast(report.GTotal_A as decimal),0),0) * 100 as A_Percent
,ISNULL(sum(report.Trn) / NULLIF(cast(report.GTotal_T as decimal),0),0) * 100 as T_Percent
,ISNULL(sum(report.Fld)/ NULLIF(cast(report.GTotal_F as decimal),0) * 100,0) as F_Percent
From
(
Select
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MajorName,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeName,'') AS VARCHAR(50))
ELSE ''
END as MinorName,
CASE #group_by
WHEN 'object' THEN csl.s_name
WHEN 'site' THEN csl.s_name
WHEN 'year' THEN CAST(YEAR(dy.Day_Stamp) AS VARCHAR(50))
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MajorVal,
CASE #group_by
WHEN 'object' THEN l.l_name
WHEN 'site' THEN ''
WHEN 'attribute' THEN CAST(coalesce(attrib.AttributeValue,'') AS VARCHAR(50))
ELSE ''
END as MinorVal,
csl.Cust_Name as Ret,l.SWVersion as Version
,d.Abn,d.Trn,d.Fld,data.GTotal_A ,data.GTotal_T,data.GTotal_F
From db_mon.dbo.CustSL csl
join db_tax.dbo.vwLane l
on (l.externalid = csl.custsl_id)
join db_mon.dbo.DaySummary dy
on (dy.Str = csl.s_name and dy.Lne = csl.l_name and year(dy.day_stamp) = year(#time_start_date) and year(dy.day_stamp) =year(#time_end_date))
Left Outer Join
(
Select a.id As AttributeId, a.attribute_name As AttributeName,
(Case When a.attribute_value_type = 'string' Then ea.string_value
Else (Case When a.attribute_value_type = 'integer' Then cast(ea.integer_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'date' Then cast(ea.date_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'boolean' Then cast(ea.boolean_value as nvarchar(100))
Else (Case When a.attribute_value_type = 'entity' Then cast(ea.ref_entity_id as nvarchar(100)) Else null End)
End)
End)
End)
End) As AttributeValue,
e.id As EntityId
From db_tax.dbo.entity_type et
Inner Join db_tax.dbo.entity As e on et.id = e.entity_type_id
Inner Join db_tax.dbo.entity_attribute As ea on e.id = ea.entity_id
Inner Join db_tax.dbo.attribute As a on ea.attribute_id = a.id
WHERE et.entity_type_name in ('Sticker','Label') And
a.id = (case WHEN #attribute_id = '' then 1 else cast(#attribute_id as int) end)
) AS attrib
On attrib.EntityId = l.L_Id
inner join db_mon.dbo.DaySummary d
on (csl.Cust_Name = d.Ret and csl.s_name = d.stckr and csl.l_name = d.label and l.SWVersion = d.Version)
join (
SELECT Ret,version,sum(Abn) as GTotal_A,sum(Trn) as GTotal_T,sum(Fld) as GTotal_F
from db_mon.dbo.DaySummary
where day_stamp >= #time_start_date and day_stamp <=#time_end_date
GROUP BY Ret,version
) data
on (d.Ret = data.Ret and l.SWVersion = data.Version)
WHERE (CHARINDEX(',' + CONVERT(VARCHAR,l.S_Id) + ',','xxx,' + #entities + ',xxx')>0 OR CHARINDEX(',' + CONVERT(VARCHAR,l.L_Id) + ',','xxx,' + #entities + ',xxx')>0)
and d.day_stamp >= #time_start_date
and d.day_stamp <=#time_end_date
) As report
Group By report.Ret,report.Version,report.MajorName,report.MinorName,report.MajorVal,report.MinorVal
,report.GTotal_A,report.GTotal_T,report.GTotal_F
)data
order By data.Ret,data.Version,batchStore,data.MajorName,data.MinorName,data.MajorVal,data.MinorVal
Does using a lot of join causes the slow execution?
SUB Select queries will always be slower then proper joins.
You are running 3 sub selects deep. This is going to impact your performance regardless of changing indexes etc.
You need to rewrite the whole thing to stop using sub selects.