SQL equivalent when PIVOT is not available in SQL Server CE - sql

I have a problem with a SQL query that runs correctly except on Microsoft SQL Server CE (no PIVOT support). The query is the following:
SELECT
*, [1] as IMGN1, [2] as IMGN2, [3] as IMGN3,
[4] as IMGN4, [5] as IMGN5, [6] as IMGN6,
[7] as IMGN7, [8] as IMGN8, [9] as IMGN9,
[10] as IMGN10
FROM
(SELECT
area.CoilId as CID, area.DEFECTID,
(SELECT SUM(s2.endposmd - s2.startposmd)
FROM sections s2
WHERE s2.OutCoilID = 999999
AND s2.InCoilId <= area.coilid) AS POSITIONMD,
d1.DNO as CAMERADEFECTNO, d1.IMAGE_NO as IMAGE_NO,
area.MERGEDTO as MERGEDTO
FROM
(OutCoils AS oc
INNER JOIN
sections AS s ON oc.OutCoilId = s.OutCoilId
INNER JOIN
defects AS area ON area.coilid = s.InCoilId
AND area.PositionMD >= s.StartPosMD
AND area.PositionMD <= s.EndPosMD
INNER JOIN
defects AS d1 ON d1.CoilId = area.CoilId
AND d1.MergedTo = area.DEFECTID)
WHERE
oc.OutCoilID = 999999 AND area.MergedTo = -2) AS SourceTable
PIVOT
(MIN([CAMERADEFECTNO]) FOR [IMAGE_NO]
IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])
) AS PivotTable
ORDER BY
PositionMD;
How can this be translated to a valid SQL query for non PIVOT editions?
I tried something using CASE but I have a problem with the subquery inside the aggregate function I use to get POSITIONMD, the rest is already working properly. Any idea of how to get POSITIONMD?
SELECT
area.DEFECTID as DEFECTID,
min(CASE when d1.MERGEDTO = area.DEFECTID then area.COILID end) CID,
min(CASE when d1.MERGEDTO = area.DEFECTID then area.MERGEDTO end) MERGEDTO,
min(CASE when d1.MERGEDTO = area.DEFECTID then (select sum(s2.endposmd - s2.startposmd) from sections s2 where s2.OutCoilID=999999 and s2.InCoilId<=area.coilid) end) POSITIONMD,
sum(CASE when d1.IMAGE_NO = 1 then (d1.DNO) end) IMGN1,
sum(CASE when d1.IMAGE_NO = 2 then (d1.DNO) end) IMGN2,
sum(CASE when d1.IMAGE_NO = 3 then (d1.DNO) end) IMGN3,
sum(CASE when d1.IMAGE_NO = 4 then (d1.DNO) end) IMGN4,
sum(CASE when d1.IMAGE_NO = 5 then (d1.DNO) end) IMGN5,
sum(CASE when d1.IMAGE_NO = 6 then (d1.DNO) end) IMGN6,
sum(CASE when d1.IMAGE_NO = 7 then (d1.DNO) end) IMGN7,
sum(CASE when d1.IMAGE_NO = 8 then (d1.DNO) end) IMGN8,
sum(CASE when d1.IMAGE_NO = 9 then (d1.DNO) end) IMGN9,
sum(CASE when d1.IMAGE_NO = 10 then (d1.DNO) end) IMGN10
FROM ( steinb.OutCoils AS oc
INNER JOIN steinb.sections AS s ON oc.OutCoilId=s.OutCoilId
INNER JOIN steinb.defects AS area ON area.coilid=s.InCoilId AND area.PositionMD>=s.StartPosMD AND area.PositionMD<=s.EndPosMD
INNER JOIN steinb.defects AS d1 ON d1.CoilId=area.CoilId AND d1.MergedTo=area.DEFECTID AND d1.IMAGE_NO!=0)
WHERE oc.OutCoilID=999999 GROUP BY area.DEFECTID ORDER BY PositionMD;
Thank you a lot.

Gotcha. I believe you just need to remove the MIN:
SELECT
DEFECTID = area.DEFECTID
, CID = MIN(CASE when d1.MERGEDTO = area.DEFECTID then area.COILID end)
, MERGEDTO = MIN(CASE when d1.MERGEDTO = area.DEFECTID then area.MERGEDTO end)
, POSITIONMD = CASE when d1.MERGEDTO = area.DEFECTID then (select sum(s2.endposmd - s2.startposmd) from sections s2 where s2.OutCoilID=999999 and s2.InCoilId<=area.coilid) END
, IMGN1 = sum(CASE when d1.IMAGE_NO = 1 then (d1.DNO) END)
, IMGN2 = sum(CASE when d1.IMAGE_NO = 2 then (d1.DNO) end)
, IMGN3 = sum(CASE when d1.IMAGE_NO = 3 then (d1.DNO) end)
, IMGN4 = sum(CASE when d1.IMAGE_NO = 4 then (d1.DNO) end)
, IMGN5 = sum(CASE when d1.IMAGE_NO = 5 then (d1.DNO) end)
, IMGN6 = sum(CASE when d1.IMAGE_NO = 6 then (d1.DNO) end)
, IMGN7 = sum(CASE when d1.IMAGE_NO = 7 then (d1.DNO) end)
, IMGN8 = sum(CASE when d1.IMAGE_NO = 8 then (d1.DNO) end)
, IMGN9 = sum(CASE when d1.IMAGE_NO = 9 then (d1.DNO) end)
, IMGN10 = sum(CASE when d1.IMAGE_NO = 10 then (d1.DNO) end)
FROM ( steinb.OutCoils AS oc
INNER JOIN steinb.sections AS s ON oc.OutCoilId=s.OutCoilId
INNER JOIN steinb.defects AS area ON area.coilid=s.InCoilId AND area.PositionMD>=s.StartPosMD AND area.PositionMD<=s.EndPosMD
INNER JOIN steinb.defects AS d1 ON d1.CoilId=area.CoilId AND d1.MergedTo=area.DEFECTID AND d1.IMAGE_NO!=0)
WHERE oc.OutCoilID=999999 GROUP BY area.DEFECTID ORDER BY PositionMD;

Related

How to Combine two pivot tables when both the tables are combined by inner Join function

Tag
SELECT TOP (1000) [System_Order_Id]
,[Batch_No]
,[Material_Code]
,[Set_Weight]
,[Actual_Weight]
FROM [master].[dbo].[Consumption_Report]
Batch No
System Id
Material Code
Set Weight
Actual Weight
1
1
1
Mat01
100
99
2
1
1
Mat02
50
55
3
1
1
Mat03
80
35
4
1
1
Mat04
40
20
SELECT TOP (1000)[Batch_End_TimeStamp]
,[Machine_Code]
, [User_Order_Id]
,[Batch_No]
,[Recipe_Code]
,[Cycle_Time]
,[System_Mode]
FROM [master].[dbo].[Batch_Report]
System Id
Batch No
Machine_Code
Recipe_Code
Cycle_Time
1
1
1
23
AA01
532
My Code:
WITH Consumption_Report AS (
SELECT
t1.Material_Code,
t1.Set_Weight,
t2.Batch_End_TimeStamp,
t2.Machine_Code,
t2.User_Order_Id,
t2.Recipe_Code,
t2.Cycle_Time
FROM
dbo.Consumption_Report t1
INNER JOIN dbo.Batch_Report t2 ON t2.Batch_No = t1.Batch_No
)
SELECT *
FROM Consumption_Report
PIVOT (AVG(Set_Weight) FOR Material_Code IN (Mat01,Mat02,Mat03,Mat04)) P
I want output like this:
Batch No
System Id
Machine_Code
Recipe_Code
Cycle_Time
Mat 01 Set Weight
Mat 01 Actual Weight
Mat 02 Set Weight
Mat 02 Actual Weight
Mat 03 Set Weight
Mat 03 Actual Weight
Mat 04 Set Weight
Mat 04 Actual Weight
1
1
1
23
AA01
532
100
99
50
55
80
35
40
20
I don't see what the second table has to do with anything. Just use conditional aggregation:
select Id, Batch_No, System_Id,
max(case when Material_Code = 'Mat01' then set_weight end) as mat01_set_weight,
max(case when Material_Code = 'Mat01' then actual_weight end) as mat01_actual_weight,
max(case when Material_Code = 'Mat02' then set_weight end) as mat02_set_weight,
max(case when Material_Code = 'Mat02' then actual_weight end) as mat02_actual_weight,
max(case when Material_Code = 'Mat03' then set_weight end) as mat03_set_weight,
max(case when Material_Code = 'Mat03' then actual_weight end) as mat03_actual_weight,
max(case when Material_Code = 'Mat04' then set_weight end) as mat04_set_weight,
max(case when Material_Code = 'Mat04' then actual_weight end) as mat04_actual_weight
from Consumption_Report
group by Id, Batch_No, System_Id;
SELECT * FROM Batch_Report
INNER JOIN (
select Batch_No,
sum(case when Material_Code = 'Mat01' then Set_Weight else 0 end) as Mat01,
sum(case when Material_Code = 'Mat01' then Actual_Weight else 0 end) as
Mat01_Act,
sum(case when Material_Code = 'Mat02' then Set_Weight else 0 end) as Mat02,
sum(case when Material_Code = 'Mat02' then Actual_Weight else 0 end) as
Mat02_Act,
sum(case when Material_Code = 'Mat03' then Set_Weight else 0 end) as Mat03,
sum(case when Material_Code = 'Mat03' then Actual_Weight else 0 end) as
Mat03_Act,
sum(case when Material_Code = 'Mat04' then Set_Weight else 0 end) as Mat04,
sum(case when Material_Code = 'Mat04' then Actual_Weight else 0 end) as Mat04_Act
from Consumption_Report
group by Batch_No) Consumption_Report
ON Batch_Report.Batch_No = Consumption_Report.Batch_No;

I am trying to add 2 values in a SQL Select Statement

SELECT f.CaseId
, SUM(CASE WHEN f.FeeType = 29 THEN f.UnitCost END) AS AdminFee
, SUM(CASE WHEN f.FeeType = 1 THEN f.UnitCost END) AS SubFee
, SUM(CASE WHEN f.FeeType = 15 THEN f.UnitCost END) AS ContFee
FROM dbo.Fee f
GROUP BY f.CaseId
For the above query I am trying to add the UnitCost where FeeType=29 and FeeType=1 within the same select statement and Store it in TotalCost.
either you add a new line
sum (case when f.FeeType IN (1, 29) then f.UnitCost END) as TotalCost
or you use your query as a subquery and make an addition
select
CaseId,
AdminFee,
SubFee,
ContFee,
AdminFee + SubFee as TotalCost
from (
SELECT f.CaseId
, SUM(CASE WHEN f.FeeType = 29 THEN f.UnitCost END) AS AdminFee
, SUM(CASE WHEN f.FeeType = 1 THEN f.UnitCost END) AS SubFee
, SUM(CASE WHEN f.FeeType = 15 THEN f.UnitCost END) AS ContFee
FROM dbo.Fee f
GROUP BY f.CaseId) s

Sum data for many different results for same field

I am trying to find a better way to write this sql server code 2008. It works and data is accurate. Reason i ask is that i will be asked to do this for several other reports going forward and want to reduce the amount of code to upkeep going forward.
How can i take a field where i sum for the yes/no/- (dash) in each field without doing an individual sum as i have in code. Each table is a month of detail data which i sum using in a CTE. i changed the table name for each month and Union All to put data together. Is there a better way to do this. This is a small sample of code. Thanks for the help.
WITH H AS (
SELECT 'August' AS Month_Name
, SUM(CASE WHEN G.FFS = '-' THEN 1 ELSE 0 END) AS FFS_Dash
, SUM(CASE WHEN G.FFS = 'Yes' THEN 1 ELSE 0 END) AS FFS_Yes
, SUM(CASE WHEN G.FFS = 'No' THEN 1 ELSE 0 END) AS FFS_No
, SUM(CASE WHEN G.DNA = '-' THEN 1 ELSE 0 END) AS DNA_Dash
, SUM(CASE WHEN G.DNA = 'Yes' THEN 1 ELSE 0 END) AS DNA_Yes
, SUM(CASE WHEN G.DNA = 'No' THEN 1 ELSE 0 END) AS DNA_No
FROM table08 G )
, G AS (
SELECT 'July' AS Month_Name
, SUM(CASE WHEN G.FFS = '-' THEN 1 ELSE 0 END) AS FFS_Dash
, SUM(CASE WHEN G.FFS = 'Yes' THEN 1 ELSE 0 END) AS FFS_Yes
, SUM(CASE WHEN G.FFS = 'No' THEN 1 ELSE 0 END) AS FFS_No
, SUM(CASE WHEN G.DNA = '-' THEN 1 ELSE 0 END) AS DNA_Dash
, SUM(CASE WHEN G.DNA = 'Yes' THEN 1 ELSE 0 END) AS DNA_Yes
, SUM(CASE WHEN G.DNA = 'No' THEN 1 ELSE 0 END) AS DNA_No
FROM table07 G )
select * from H
UNION ALL
select * from G
How about:
SELECT Month_Name,
SUM(CASE WHEN G.FFS = '-' THEN 1 ELSE 0 END) AS FFS_Dash,
SUM(CASE WHEN G.FFS = 'Yes' THEN 1 ELSE 0 END) AS FFS_Yes,
SUM(CASE WHEN G.FFS = 'No' THEN 1 ELSE 0 END) AS FFS_No,
SUM(CASE WHEN G.DNA = '-' THEN 1 ELSE 0 END) AS DNA_Dash,
SUM(CASE WHEN G.DNA = 'Yes' THEN 1 ELSE 0 END) AS DNA_Yes,
SUM(CASE WHEN G.DNA = 'No' THEN 1 ELSE 0 END) AS DNA_No
FROM ((select 'July' as Month_Name, G.*
from table07 G
) union all
(select 'August', H.*
from table08 H
)
) gh
GROUP BY Month_Name;
However, having tables with the same structure is usually a sign of poor database design. You should have a single table with a column representing the month.

JOIN always the default value, else join the match value

I have the following SQL Server Query
select r.isactive,r.workingyear,r.startperiod,r.endperiod,r.anniversary
from setup_holiday_policy t cross apply
(select data
from dbo.Split(t.scheduleapplication, ',')
) di cross apply
(select max(case when did.id = 1 then did.data end) as isactive,
max(case when did.id = 2 then did.data end) as workingyear,
max(case when did.id = 3 then did.data end) as anniversary,
max(case when did.id = 4 then did.data end) as startperiod,
max(case when did.id = 5 then did.data end) as endperiod
from dbo.Split(di.data,':') did
) r
WHERE r.workingyear = #employeeworkingyears
The policy table can have a 0 value in the workingyear field. Meaning that when this field has 0 then is the default record I should return.
setup_holiday_policy
So, if #employeeworkingyears = 2 and there is no workingyears = 2 in setup_holiday_policy I should return the default row that has the 0 value in workingyears field.
This is a sample of the rows returned.
Any clue how to achieve this?
If only one row is going to be returned (as suggested by the sample data), you can do this using top:
select top 1 r.isactive,r.workingyear,r.startperiod,r.endperiod,r.anniversary
from setup_holiday_policy t cross apply
(select data
from dbo.Split(t.scheduleapplication, ',')
) di cross apply
(select max(case when did.id = 1 then did.data end) as isactive,
max(case when did.id = 2 then did.data end) as workingyear,
max(case when did.id = 3 then did.data end) as anniversary,
max(case when did.id = 4 then did.data end) as startperiod,
max(case when did.id = 5 then did.data end) as endperiod
from dbo.Split(di.data,':') did
) r left outer join
(select #employeeworkingyears as employeeworkingyears
) e
on
WHERE r.workingyear in (#employeeworkingyears, 0)
order by r.workingyear desc;

Using WHERE to filter a CASE statement

I would like to filter the result set on the variables that are listed in the CASE statements.
SELECT u.id,
max(t.request_at) AS "Date",
sum(CASE
WHEN t.view = 1 THEN 1
ELSE 0 END) AS ONE,
sum(CASE
WHEN t.view = 2 THEN 1
ELSE 0 END) AS TWO,
sum(CASE
WHEN t.view = 3 THEN 1
ELSE 0 END) AS THREE
FROM users u
JOIN t ON u.id = t.uid
WHERE u.signup_city_id = 18
AND u.creationtime BETWEEN '2013-12-01' AND '2014-01-01'
group by 1
I would really like to filter something along the lines of: WHERE ONE < 3
i.e. Where the column one is smaller than 3.
You would use a having clause:
SELECT u.id, max(t.request_at) AS "Date",
sum(CASE WHEN t.view = 1 THEN 1 ELSE 0 END) AS ONE,
sum(CASE WHEN t.view = 2 THEN 1 ELSE 0 END) AS TWO,
sum(CASE WHEN t.view = 3 THEN 1 ELSE 0 END) AS THREE
FROM users u JOIN
t
ON u.id = t.uid
WHERE u.signup_city_id = 18 AND u.creationtime BETWEEN '2013-12-01' AND '2014-01-01'
group by 1
HAVING sum(CASE WHEN t.view = 1 THEN 1 ELSE 0 END) < 3;
Or use a subquery:
SELECT t.*
FROM (SELECT u.id, max(t.request_at) AS "Date",
sum(CASE WHEN t.view = 1 THEN 1 ELSE 0 END) AS ONE,
sum(CASE WHEN t.view = 2 THEN 1 ELSE 0 END) AS TWO,
sum(CASE WHEN t.view = 3 THEN 1 ELSE 0 END) AS THREE
FROM users u JOIN
t
ON u.id = t.uid
WHERE u.signup_city_id = 18 AND u.creationtime BETWEEN '2013-12-01' AND '2014-01-01'
group by 1
) t
WHERE ONE < 3;
You need to wrap it into a derived table:
select *
from (
SELECT u.id,
max(t.request_at) AS "Date",
sum(CASE
WHEN t.view = 1 THEN 1
ELSE 0 END) AS ONE,
sum(CASE
WHEN t.view = 2 THEN 1
ELSE 0 END) AS TWO,
sum(CASE
WHEN t.view = 3 THEN 1
ELSE 0 END) AS THREE
FROM users u
JOIN t ON u.id = t.uid
WHERE u.signup_city_id = 18
AND u.creationtime BETWEEN '2013-12-01' AND '2014-01-01'
group by 1
) t
WHERE ONE < 3
You can use the result of the SUM of the CASE statement in your WHERE clause like this:
SELECT u.id,
max(t.request_at) AS "Date",
SUM(CASE
WHEN t.view = 1 THEN 1
ELSE 0 END) AS ONE,
SUM(CASE
WHEN t.view = 2 THEN 1
ELSE 0 END) AS TWO,
SUM(CASE
WHEN t.view = 3 THEN 1
ELSE 0 END) AS THREE
FROM users u
JOIN t ON u.id = t.uid
WHERE u.signup_city_id = 18
AND u.creationtime BETWEEN '2013-12-01' AND '2014-01-01'
GROUP BY 1
HAVING SUM(CASE
WHEN t.view = 1 THEN 1
ELSE 0 END) < 3