TSQL Pivot with combination result - tsql

I have data in SQL server 2005 table similar to below format.
OrderNo ProductId Sale
----------------------
1 A £10
2 B £20
3 C £30
4 A £10
4 B £20
5 A £10
5 B £20
6 C £30
6 B £20
7 C £30
I need to write TSQL query that would give me result table in this format.
NoOfOrders 'A' SaleValue 'B' SaleValue 'C' SaleValue
------------------------------------------------
Prod A (Only) 1 £10
Prod B (Only) 1 £20
Prod C (Only) 2 £60
Prod A & B 2 £20 £40
Prod A & C 0 £0 £0 £0
Prod B & C 1 £20 £30
Any idea greatly appreciated.

I'd suggest a three-step approach:
(1) SELECT distinct ProductID into a table variable.
(2) CROSS JOIN the table variable on itself to get all possible combinations.
(3) Craft a dynamic SQL statement to pivot it out.

Related

Functional update - multivariable function with dynamic columns

Any help with the following would be much appreciated!
I have two tables: table1 is a summary table whilst table2 is a list of all data points. I want to be able to summarise the information in table2 for each row in table1.
table1:flip `grp`constraint!(`a`b`c`d; 10 10 20 20);
table2:flip `grp`cat`constraint`val!(`a`a`a`a`a`b`b`b;`cl1`cl1`cl1`cl2`cl2`cl2`cl2`cl1; 10 10 10 10 10 10 20 10; 1 2 3 4 5 6 7 8);
function:{[grpL;constraintL;catL] first exec total: sum val from table2 where constraint=constraintL, grp=grpL,cat=catL};
update cl1:function'[grp;constraint;`cl1], cl2:function'[grp;constraint;`cl2] from table1;
The fourth line of this code achieves what I want for the two categories:cl1 and cl2
In table1 I want to name a new column with the name of the category (cl1, cl2, etc.) and I want the values in that column to be the output from running the function over that column.
However, I have hundreds of different categories, so don't want to have to list them out manually as in the fourth line. How would I pass in a list of categories, e.g. below?
`cl1`cl2`cl3
Sticking to your approach, you would just have to make your update statement functional and then iterate over the columns like so:
{![`table1;();0b;(1#x)!enlist ((';function);`grp;`constraint;1#x)]} each `cl1`cl2
Assuming you can amend table1 in place. If you must retain the original table1 then you can pass it by value though it will consume more memory
{![x;();0b;(1#y)!enlist ((';function);`grp;`constraint;1#y)]}/[table1;`cl1`cl2]
Another approach would be to aggregate, pivot and join though it's not necessarily a better solution as you get nulls rather than zeros
a:select sum val by cat,grp,constraint from table2
p:exec (exec distinct cat from a)#cat!val by grp,constraint from a
table1 lj p
There are several different methods you can look into.
The easiest method would be a functional update - http://code.kx.com/wiki/JB:QforMortals2/queries_q_sql#Functional_update
Below, though, should somewhat prove more useful, quicker and neater:
Your problem can be split into 2 parts. For the first part, you are looking to create a sum of each category by grp and constraint within table2. As for the second part, you are looking to join these results (the lookups) onto the corresponding records from table1.
You can create the necessary groups using by
q)exec val,cat by grp,constraint from table2
grp constraint| val cat
--------------| ------------------------------
a 10 | 1 2 3 4 5 `cl1`cl1`cl1`cl2`cl2
b 10 | 6 8 `cl2`cl1
b 20 | ,7 ,`cl2
Note though, this will only create nested lists of the columns in your select query
Next is to sum each of the cat groups
q)exec sum each val group cat by grp,constraint from table2
grp constraint|
--------------| ------------
a 10 | `cl1`cl2!6 9
b 10 | `cl2`cl1!6 8
b 20 | (,`cl2)!,7
Then, to create the cat's columns you can use a pivot like syntax - http://code.kx.com/wiki/Pivot
q)cats:asc exec distinct cat from table2
q)exec cats#sum each val group cat by grp,constraint from table2
grp constraint| cl1 cl2
--------------| -------
a 10 | 6 9
b 10 | 8 6
b 20 | 7
Now you can use this lookup table and index into each row from table1
q)(exec cats#sum each val group cat by grp,constraint from table2)[table1]
cl1 cl2
-------
6 9
8 6
To fill the nulls with zeros, use the carat symbol - http://code.kx.com/wiki/Reference/Caret
q)0^(exec cats#sum each val group cat by grp,constraint from table2)[table1]
cl1 cl2
-------
6 9
8 6
0 0
0 0
And now you can join on each row from table1 to your results using join-each
q)table1,'0^(exec cats#sum each val group cat by grp,constraint from table2)[table1]
grp constraint cl1 cl2
----------------------
a 10 6 9
b 10 8 6
c 20 0 0
d 20 0 0
HTH, Sean
This approach is the easiest way to pass in a list of categories
{table1^flip x!function'[table1`grp;table1`constraint;]each x}`cl1`cl2

Different set of unnest not showing correctly?

Example Data
Sql fiddle http://sqlfiddle.com/#!15/c8a17/4
My Query
select
unnest(array[g,g1,g2]) as disp,
unnest(array[g,g||'-'||g1,g||'-'||g1||'-'||g2]) as grp,
unnest(array[1,2,3]) as ord,
unnest(array['assesvalue','lst2','salesvalue','itemprofit','profitper','itemstockvalue'])as analysis,
unnest(array[value1,tt,sv,tp,per,tsv])as val
from (
select
g,
g1,
g2,
sum(value1) as value1,
sum(tt) as tt,
sum(sv) as sv,
sum(tp) as tp,
sum(per) as per,
sum(tsv) as tsv
from table1
group by g,g1,g2
) as ta
It Show the output like this
disp grp ord analysis val
A A 1 assesvalue 100
B A-B 2 lst2 30
C A-B-C 3 salesvalue 20
A A 1 itemprofit 5
B A-B 2 profitper 1
C A-B-C 3 itemstockvalue 10
Expected Result :
disp grp ord analysis val
A A 1 assesvalue 100
A A 1 lst2 30
A A 1 salesvalue 20
A A 1 itemprofit 5
A A 1 profitper 1
A A 1 itemstockvalue 10
B A-B 2 assesvalue 100
B A-B 2 lst2 30
B A-B 2 salesvalue 20
B A-B 2 itemprofit 5
B A-B 2 profitper 1
B A-B 2 itemstockvalue 10
C A-B-C 3 assesvalue 100
C A-B-C 3 lst2 30
C A-B-C 3 salesvalue 20
C A-B-C 3 itemprofit 5
C A-B-C 3 profitper 1
C A-B-C 3 itemstockvalue 10
In Query i am using multiple unnest.
first 3 unnest inside have 3 columns other have 6 columns that its show wrong output but if last 2 unnest have less then 6 its show my expected result.
what am doing wrong in query??
i am using postgresql 9.3

Get Data from 2 Tables using Join

I have 2 tables :
1. transfer
2. data
in table data 2 records :
id name
1. 2 PQR
2. 3 XYZ
in table transfer 5 records :
id to from amount type
1. 1 2 3 100.00 C
2. 2 3 2 200.00 C
3. 3 2 3 150.00 D
4. 4 3 2 150.00 C
5. 5 2 3 300.00 D
now I want to form query that will take 2 in where condition and give me result
from transfer table that when 2 is in to column then from data should be shown
and when 2 is in from column then to data should be print.
And in result I want other columns that are amount and type.
I want data using join (Any), I am totally confused that how to perform this task.
Expected Result :
from/to amount type
3 100.00 C
3 200.00 C
3 150.00 D
3 300.00 D
Any Guidance on this..
Try Like this
select
case when "from"=2 then "to" when "to"=2 then "from" end "from/to"
,amount,type from transfer
Out put is
form/to amount type
3 100 C
3 200 C
3 150 D
3 150 C
3 100 D
OR
select case when "from"=2 then d.name when "to"=2 then data.name end "from/to",
amount,type from transfer inner join data on ("to"=data.id)
inner join data as d on("from"=d.id)
Out put is
form/to amount type
XYZ 100 C
XYZ 200 C
XYZ 150 D
XYZ 150 C
XYZ 100 D
ADDITION:
prove of working query: http://ideone.com/64kIov

How to Sum Groups and provide totals in separate columns?

I have beek looking at this problem for a while and while i know i could do this programiticly in LINQ. I started thinking about solutions that would scale if this were a vary large data set. I'm building my experieance with SQL and believe there is a way to get the result with out performing an insert.
What I have is data that looks like this:
ids type total
A01 x 1
A01 x 2
A01 x 3
A01 y 4
B01 y 2
B01 x 3
B01 y 1
C01 x 1
C01 y 2
C01 x 5
C01 y 6
What I want is data that looks like this:
id x total y total
A01 6 4
B01 3 3
C01 6 8
I's my belief incorrect?
...
SUM(CASE type WHEN'x' THEN total ELSE 0 END),
SUM(CASE type WHEN 'y' THEN total ELSE 0 END)
...
Group by
Id
Sorry hard to give full answer on phone
This is called a pivot table, and there are a number of ways to accomplish it.
If you're using SQL Server 2005 or later, the PIVOT operator (MSDN) is a neat option:
select id, [x], [y]
from temp d
PIVOT ( sum(total) for type in ([x],[y]) ) p

simplest way to do recursive t-sql for multiple selects

I am developing a Bill Of Materials cost calculator program and I am struggling to fathom a simple solution to some recursive selects I want.
I am using SQL Server 2005 for this part of the application.
Say I have Product A, which contains assembly B, and Part C. Assembly B will contain parts D and E, but, here is where I struggle, D and or E may contain X number of other assemblies.
I can do something along the lines of;
SELECT * FROM TBLBOM WHERE Parent = A
UNION
SELECT * FROM TBLBOM WHERE Parent = B
UNION
SELECT * FROM TBLBOM WHERE Parent = C
To produce something along the lines of;
PARENT COMP COST
A X £1
B D £0.5
B E £0.5
....
C Y £1
But lets say Component D is made up of Component F & G, how would I accommodate this in a t-sql statement.
In a nutshell, I need to expand out the full component list of all assemblies that are associated to a parent product regardless of whether they are in a sub assembly or a sub assembly of a sub assembly etc...
Ideally I would like to avoid a cursor at all costs :)
Any help / guidance would be appreciated.
Thank you.
EDIT;
As requested, here is the table structure and expected output. The parent is the DRAWINGNO and the child node is the PART (which could also be a parent in itself);
BOMID DRAWINGNO ITEM PART COST
1303 HGR05180 1 HGR05370 1
1304 HGR05180 2 HGF65050 4
1305 HGR05180 3 HGF50340 1
1312 HGR05370 1 HPN05075 1
1313 HGR05370 2 HPN05085 2
1314 HGR05370 3 HPN05080 1
1848 EXP-18G 1 HGR05180 1
1849 EXP-18G 2 HGR05210 3
1850 EXP-18G 3 HGR05230 1
1851 EXP-18G 4 HGR05140 1
1852 EXP-18G 5 HGR05150 2
1853 EXP-18G 6 HGR05050 1
1854 EXP-18G 7 ESC05350 1
1855 EXP-18G 8 ESC05330 3
1856 EXP-18G 9 HGR05360 1
1857 EXP-18G 10 HGR05370 2
1858 EXP-18G 11 ESC05640 1
If i understand (and without table structure) you can try something like this
DECLARE #Table TABLE(
Component VARCHAR(50),
Parent VARCHAR(50),
Cost FLOAT
)
INSERT INTO #Table SELECT 'B', 'A', 1
INSERT INTO #Table SELECT 'C', 'B', 2
INSERT INTO #Table SELECT 'C', 'B', 3
INSERT INTO #Table SELECT 'D', 'C', 4
DECLARE #Product VARCHAR(50)
SET #Product = 'A'
;WITH Selects AS (
SELECT *
FROM #Table
WHERE Parent = #Product
UNION ALL
SELECT t.*
FROM #Table t INNER JOIN
Selects s ON t.Parent = s.Component
)
SELECt *
FROm Selects
You want to be using recursive common table expression (CTEs). Books Online has a lot of information on how to use these; in the index, look up CTEs and pick the "Recursive Queries Using Common Table Expressions" entry. (I've had problems before linking to BOL online, or I'd try to link it here.)
Also, if you post your table structure, you should get half a dozen examples within five minutes. Better yet, try and search SO for prior examples.