How to use multiple columns in pivot? - sql-server

I have this query
SELECT [b].[BillID],
[b].[BillingCode],
[bc].[CurrentUsage],
[bc].[Rate],
[bc].[CurrentCost],
[c].[Title]
INTO #Temp
FROM [dbo].[Bills] AS [b]
INNER JOIN [dbo].[BillCosts] AS [bc] ON [bc].[BillIDRef] = [b].[BillID]
INNER JOIN [Base].[Costs] AS [c] ON [c].[CostID] = [bc].[CostIDRef]
this is result
BillID BillingCode CurrentUsage Rate CurrentCost Title
----------- -------------------- ------------ ----------- ----------- ------
5 44545455 10 20 30 AvgTimes
5 44545455 40 50 60 MaxTimes
I need this result:
BillID BillingCode AvgTimes Cost MaxTimes Cost AvgTimes Rate MaxTimes Rate AvgTimes Usage MaxTimes Usage
----------- -------------------- -------------- -------------- -------------- ------------- -------------- ---------------
5 44545455 30 60 20 50 10 40
Is it possible using pivot on multiple columns CurrentUsage,Cost,Rate?
If isn't possible using pivot, How to write query?

You can use conditional aggregation:
SELECT [b].[BillID],
[b].[BillingCode],
MAX(CASE WHEN [c].[Title] = 'AvgTimes' THEN [bc].[CurrentUsage] END) AS [AvgTimes Usage],
MAX(CASE WHEN [c].[Title] = 'MaxTimes' THEN [bc].[CurrentUsage] END) AS [MaxTimes Rate],
MAX(CASE WHEN [bc].[Title] = 'AvgTimes' THEN [bc].[Rate] END) AS [AvgTimes Rate],
MAX(CASE WHEN [bc].[Title] = 'MaxTimes' THEN [bc].[Rate] END) AS [MaxTimes Usage],
MAX(CASE WHEN [bc].[Title] = 'AvgTimes' THEN [bc].[CurrentCost] END) AS [AvgTimes CurrentCost],
MAX(CASE WHEN [bc].[Title] = 'MaxTimes' THEN [bc].[CurrentCost] END) AS [MaxTimes CurrentCost]
INTO #Temp
FROM [dbo].[Bills] AS [b]
INNER JOIN [dbo].[BillCosts] AS [bc] ON [bc].[BillIDRef] = [b].[BillID]
INNER JOIN [Base].[Costs] AS [c] ON [c].[CostID] = [bc].[CostIDRef]
GROUP BY [b].[BillID], [b].[BillingCode]

Related

Group value via range and value sql query

I have two table .
Table1 have following fields.
From To id
---- ---- ----
0 0 1
1 5 2
5 10 3
10 15 4
Table 2:
Table 1 ID Value
--------- -------
1 10
2 10
3 15
4 10
current output:
from To Value
----- ------ -------
0 15 10
5 10 15
Required Output
From To Value
------ ---- ------
0 5 10
5 10 15
10 15 10
How get the output like
code
SELECT MIN(DiscountFrom) FromDiscount ,
MAX(DiscountTo) Todiscount ,
Amount
FROM table1 t1
JOIN table2 t2 ON t1.id = t2.id
GROUP BY Amount
Here for me grouping makes no sense so, i used lead() function to access next record if 0 found
select distinct
case when t.[from] = 1 then 0 else t.[from] end [from],
case when t.[to] = 0 then lead(t.[to]) over (order by t.id) else t.[to] end [to],
t1.value
from table1 t
join table2 t1 on t1.id = t.id
Result :
from to value
0 5 10
5 10 15
10 15 10
It looks like your data is inconsistent, for this to work i had to change the first record to
From To id
---- ---- ----
0 1 1
then this works for all cases
;WITH test1
AS (SELECT
t.id
,[from]
,[to]
,value
FROM
table1 t
JOIN table2 t1
ON t1.id = t.id),
MyTest
AS (SELECT
Anchor.[from]
,Anchor.[To]
,Anchor.value
,1 AS Grp
FROM
test1 AS Anchor
WHERE
[From] = 0
UNION ALL
SELECT
Child.[from]
,Child.[To]
,Child.value
,CASE WHEN Mytest.value = child.value THEN 0 ELSE 1 END + MyTest.Grp AS grp
FROM
test1 AS Child
INNER JOIN MyTest
ON Mytest.[To] = child.[From])
SELECT
Min([From]) AS [From]
,Max([To]) AS [To]
,Max(Value) AS Value
FROM
mytest
GROUP BY
Grp

How to fetch record from two tables specify column name based on second table row records

I need query which fetch records from two tables but column name should be based on records in second table.
Details are below
My first table
Emp Table
emp_id emp_name
1 Abc
2 XYZ
3 PQR
My second table
Salary Table
id emp_id month salary
1 1 1 4000
2 1 2 3000
3 2 1 5000
4 2 2 4500
I need output like,
emp_id emp_name jan feb
1 Abc 4000 3000
2 XYZ 5000 4500
I am able to achieve this by using left join but for every month I need to add it in query like,
select e.emp_id,e.emp_name,j.month as Jan,f.month as Feb from emp e
Left Join salary j on e.emp_id=j.emp_id and j.month=1
Left Join salary f on e.emp_id=f.emp_id and f.month=2
Above work for me But which is not feasible. I have master table for month also.
Month Table
id Name
1 Jan
2 Feb
3 March
5 April
I want fetch record for for specific month currently for (Jan & feb).
Please help me achieve this faster way.
Using conditional aggregation:
SELECT
e.emp_id,
e.emp_name,
[Jan] = MAX(CASE WHEN s.[month] = 1 THEN s.salary END),
[Feb] = MAX(CASE WHEN s.[month] = 2 THEN s.salary END),
[Mar] = MAX(CASE WHEN s.[month] = 3 THEN s.salary END),
[Apr] = MAX(CASE WHEN s.[month] = 4 THEN s.salary END),
[May] = MAX(CASE WHEN s.[month] = 5 THEN s.salary END),
[Jun] = MAX(CASE WHEN s.[month] = 6 THEN s.salary END),
[Jul] = MAX(CASE WHEN s.[month] = 7 THEN s.salary END),
[Aug] = MAX(CASE WHEN s.[month] = 8 THEN s.salary END),
[Sep] = MAX(CASE WHEN s.[month] = 9 THEN s.salary END),
[Oct] = MAX(CASE WHEN s.[month] = 10 THEN s.salary END),
[Nov] = MAX(CASE WHEN s.[month] = 11 THEN s.salary END),
[Dec] = MAX(CASE WHEN s.[month] = 12 THEN s.salary END)
FROM Emp e
LEFT JOIN Salary s
ON s.emp_id = e.emp_id
GROUP BY
e.emp_id, e.emp_name
ONLINE DEMO

SQL PIVOT on a variable amount of rows

I have the following data on a MSSQL Server:
Item No_ Unit Of Measure Qty Per Base UoM Rounding Precision
000001 PIECE 1 1.0
000001 PALLET 100 1.0
000001 BOX 12 1.0
000002 KG 1 1.0
000002 TON 1000 0.001
I am trying to get the following output:
Item No_ UoM1 Qty pb UoM1 RP1 UoM2 Qty pb UoM2 RP2 UoM3 Qty pb UoM3 RP3
000001 PIECE 1 1.0 PALLET 100 1.0 BOX 12 1.0
000002 KG 1 1.0 TON 1000 0.0001 NULL NULL NULL
I tried achieving this using the PIVOT operator but it does not seem te be correct.
What is the correct way to achieve my desired output?
For trully generic solution you need to use Dynamic-SQL.
But you say you want starting point, so I give you one. You can use:
LiveDemo
WITH cte AS
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY Item_No_ ORDER BY (SELECT 1)) AS rn
FROM #mytable
)
select Item_No_,
max(case when rn = 1 then Unit_Of_Measure end) UoM1,
max(case when rn = 1 then Qty_Per_Base_UoM end) [Qty pb UoM1],
max(case when rn = 1 then Rounding_Precision end) RP1,
max(case when rn = 2 then Unit_Of_Measure end) UoM2,
max(case when rn = 2 then Qty_Per_Base_UoM end) [Qty pb UoM2],
max(case when rn = 2 then Rounding_Precision end) RP2,
max(case when rn = 3 then Unit_Of_Measure end) UoM3,
max(case when rn = 3 then Qty_Per_Base_UoM end) [Qty pb UoM3],
max(case when rn = 3 then Rounding_Precision end) RP3,
max(case when rn = 4 then Unit_Of_Measure end) UoM4,
max(case when rn = 4 then Qty_Per_Base_UoM end) [Qty pb UoM4],
max(case when rn = 4 then Rounding_Precision end) RP4
from cte
group by Item_No_;
The point is that if your number of units is known in advance you can create hardcoded columns from 1 .. n.
For more info search Dynamic Pivot multiple columns. It is achievable, but first try to crack this solution.

How to select PIVOT for this table?

I have a table like this:
Id Code Value
----------- -------------------- -----------
1 A 100
2 B 100
3 C 220
4 A 150
5 C 300
6 D 120
7 E 120
And this is my expectation:
Code1 Value1 Code2 Value2 Code3 Value3
----------- ----------- ----------- ----------- ----------- -----------
A 100 B 100 C 220
A 150 C 300 D 120
E 120
Should I use PIVOT to this case (and how to do this) or normal select query?
This isn't with pivot either, but in case you need to group the items into groups of 3 ordered by ID and the ID has gaps, like sometimes happen, this should do it:
select
ROW,
max(case when COL = 0 then Code end) as Code1,
max(case when COL = 0 then Value end) as Value1,
max(case when COL = 1 then Code end) as Code2,
max(case when COL = 1 then Value end) as Value2,
max(case when COL = 2 then Code end) as Code3,
max(case when COL = 2 then Value end) as Value3
FROM (
select
(row_number() over (order by ID)-1) % 3 as COL,
(row_number() over (order by ID)-1) / 3 as ROW,
Code,
Value
from
data
) X
group by ROW
This calculates row and column numbers based on row_number that increases over ID, and then uses group by to split the results into groups of 3.
SQL Fiddle
Perhaps PIVOT is not usefull here.
SELECT t1.code as code1, t1.value as value1,
t2.code as code2, t2.value as value2,
t3.code as code3, t3.value as value3
FROM tab as t1
left join tab as t2
ON t1.id = t2.id - 1
left join tab as t3
ON t2.id = t3.id - 1
where ((t1.id-1) % 3) = 0

Different order by clause for different columns

I hope my title made sense, here's a sample of my table.
My table has 1 column for a unique product barcode, and 4 date columns which is for storing what date and time a product passed an inspection area(4 of them), i removed the date in my example so just assume they're all the same dates.
Product | Time1 | Time2 | Time3 | Time4
---------------------------------------
A | 10:00 | 10:15 | 10:30 | 10:45
B | 10:05 | 10:25 | 10:35 | 10:50
C | 10:10 | 10:20 | 10:40 | 10:55
Output:
Inspect1 | Inspect2 | Inspect3 | Inspect4
-----------------------------------------
A A A A
B C B B
C B C C
In my output, I want to select the product multiple times with different order by(order by Time1, order by Time2, etc.)
I used case select to select the product multiple times, how do I put an order by so that I get something like my example above.
SELECT
CASE WHEN time1 BETWEEN '10:00' AND '11:00' THEN product END AS inspect1,
CASE WHEN time2 BETWEEN '10:00' AND '11:00' THEN product END AS inspect2,
CASE WHEN time3 BETWEEN '10:00' AND '11:00' THEN product END AS inspect3,
CASE WHEN time4 BETWEEN '10:00' AND '11:00' THEN product END AS inspect4
FROM Table
Here is a solution using ROW_NUMBER:
SQL Fiddle
WITH CteUnion(Product, TimeNum, Value) AS(
SELECT Product, 'Time1', Time1 FROM YourTable UNION ALL
SELECT Product, 'Time2', Time2 FROM YourTable UNION ALL
SELECT Product, 'Time3', Time3 FROM YourTable UNION ALL
SELECT Product, 'Time4', Time4 FROM YourTable
),
CteRN AS(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY TimeNum ORDER BY Value)
FROM CteUnion
),
CteOrd AS(
SELECT *,
Ord = ROW_NUMBER() OVER(PARTITION BY RN ORDER BY Value)
FROM CteRN
)
SELECT
Inspect1 = MAX(CASE WHEN Ord = 1 THEN Product END),
Inspect2 = MAX(CASE WHEN Ord = 2 THEN Product END),
Inspect3 = MAX(CASE WHEN Ord = 3 THEN Product END),
Inspect4 = MAX(CASE WHEN Ord = 4 THEN Product END)
FROM CteOrd
GROUP BY RN
ORDER BY RN

Resources