How to simulate UNPIVOT in Access? - sql

UNPIVOT is available in MS SQL-Server 2005, but AFAIK not in MS Access 2010. How can it be implemented with on-board means? For example, I have a table
ID | A | B | C | Key 1 | Key 2 | Key 3
---------------------------------------
1 | x | y | z | 3 | 199 | 452
2 | x | y | z | 57 | 234 | 452
and want to have a table like
ID | A | B | C | Key
--------------------
1 | x | y | z | 3
2 | x | y | z | 57
1 | x | y | z | 199
2 | x | y | z | 234
2 | x | y | z | 452
Key 452 is a special case. Currently I do the rotation in OLEDB/ATL C++. Although it is fast enough I'm still curious. What is the most efficient SQL statement for Access 2010 here?

This query ...
SELECT ID, A, B, C, [Key 1] AS key_field
FROM tblUnpivotSource
UNION ALL
SELECT ID, A, B, C, [Key 2] AS key_field
FROM tblUnpivotSource
UNION ALL
SELECT ID, A, B, C, [Key 3] AS key_field
FROM tblUnpivotSource;
... returns this recordset (using your sample table values as tblUnpivotSource) ...
ID A B C key_field
-- - - - ---------
1 x y z 3
2 x y z 57
1 x y z 199
2 x y z 234
1 x y z 452
2 x y z 452

Unfortunately there is no easy way to do this with access. You can do this by using a UNION to get each value
SELECT ID, A, B, C, [Key 1] As key
FROM Table
WHERE [Key 1] = 3
UNION ALL
SELECT ID, A, B, C, [Key 1] As key
FROM Table
WHERE [Key 1] = 57
UNION ALL
SELECT ID, A, B, C, [Key 2] As key
FROM Table
WHERE [Key 2] = 199
UNION ALL
SELECT ID, A, B, C, [Key 2] As key
FROM Table
WHERE [Key 2] = 234
UNION ALL
SELECT ID, A, B, C, [Key 3] As key
FROM Table
WHERE [Key 3] = 452

You can create a auxiliary table with all column names as values
(can use excel copy the first row of your table to excel > paste special > transpose)
Create in your table a auto increment column and index this column
Create a new cross join query like the following
SELECT ID, A, B, C
, AUX_TABLE.KEY_FIELD
, DLookUp("[" & [AUX_TABLE].[KEY_FIELD] & "]","TABLE","[ID] = " & [TABLE].[ID]) AS KEY_VALUE
FROM TABLE, AUX_TABLE;
Downside would be you have to maintain AUX_TABLE to keep that working. But if this is a one-time-thing this might be the way to go.

Related

SQL/HIVE - How do I query from a horizontal output to vertical output?

I have a query that returns two rows with the information needed
SELECT src_file_dt, a, b ,c FROM my_table WHERE src_file_dt IN ('1531675040', '1531675169');
it will return:
src_file_dt | a | b | c
1531675040 | 2 | 6 | 9
1531675169 | 8 | 2 | 0
Now, I need the data in the following layout, how do I get it like this output:
fields | prev (1531675040) | curr (1531675169)
a | 2 | 8
b | 6 | 2
c | 9 | 0
There should be easier way to achieve that.
I've build results using explode function and selecting separately data for prev and next columns:
select t1.keys, t1.vals as prev, t2.vals as next from (
SELECT explode(map('a', a, 'b', b, 'c',c)) as (keys, vals)
FROM my_table
WHERE src_file_dt = '1531675040'
) t1,
(
SELECT explode(map('a', a, 'b', b, 'c',c)) as (keys, vals)
FROM my_table
WHERE src_file_dt = '1531675169'
) t2
where t1.keys = t2.keys
;

Unpivot in Potgresql

How can I unpivot in Postgresql without using UNION? I have more than 100 columns, and I am looking for a neat way to do it.
Given table:
id c1 c2 c3
1 X Y Z
2 A B C
3 Y C Z
Desired table:
id col
1 X
1 Y
1 Z
2 A
2 B
2 C
3 Y
3 C
3 Z
Use jsonb functions:
select id, value as col
from my_table
cross join jsonb_each_text(to_jsonb(my_table))
where key <> 'id';
id | value
----+-------
1 | X
1 | Y
1 | Z
2 | A
2 | B
2 | C
3 | Y
3 | C
3 | Z
(9 rows)
Db<>Fiddle.
In Postgres 9.3 or 9.4 use to_json() and json_each_text().
In versions 9.1 or 9.2 install hstore:
create extension if not exists hstore;
select id, value as col
from my_table
cross join each(hstore(my_table))
where key <> 'id';

Find all possible pairs based on transitivity via T-SQL

I have a concern that doesn't let me go for already several days.
The collective mind is the last resort I may rely on.
Assume we have a table with two columns. Actually, the values are GUIDs, but for the sake of simplicity let's take them as letters.
| a | b |
|---|---|
| x | y |
| y | x |
| y | z |
| z | y |
| m | n |
| m | z |
I need to create a T-SQL query that will present all the possible pairs out of trasitivity, i.e. if x=y, y=z, then x=z. Also, simmetry has to be there, i.e. if there is x=y, then there should be y=x as well.
In this particular case, I believe there is "full house", meaning that every letter is connected to all others through the intermediates. But I need a query that will show that.
All I did is here (SQLFiddle fails to run it):
WITH
t AS
(SELECT 'x' AS a, 'y' AS b
UNION ALL
SELECT 'y' AS a, 'x' AS b
UNION ALL
SELECT 'y' AS a, 'z' AS b
UNION ALL
SELECT 'z' AS a, 'y' AS b
UNION ALL
SELECT 'm' AS a, 'n' AS b
UNION ALL
SELECT 'm' AS a, 'z' AS b),
coupled_reflective AS --for reflective couples we take either of them
(SELECT t2.a, t2.b
FROM t t1
JOIN t t2 ON t1.a=t2.b
AND t1.b!=t2.a),
reversive_coupled_reflective AS --that's another half of the above couples (reversed)
(SELECT t2.b, t2.a
FROM t t1
JOIN t t2 ON t1.a=t2.b
AND t1.b!=t2.a),
rs AS -- reduce the initial set (t)
(SELECT *
FROM coupled_reflective
UNION
SELECT *
FROM t
EXCEPT
SELECT *
FROM reversive_coupled_reflective),
cte AS -- recursively iterate through the set to find transitive values (get linked by the left field)
(SELECT a, b
FROM rs
UNION ALL
SELECT rs.b, cte.b
FROM rs
JOIN cte ON rs.a=cte.a
AND rs.b!=cte.b),
cte2 AS -- recursively iterate through the set to find transitive values (get linked by the right field)
(SELECT a, b
FROM rs
UNION ALL
SELECT rs.a, cte.a
FROM rs
JOIN cte ON rs.b=cte.b
AND rs.a!=cte.a)
SELECT a, b FROM cte2
UNION
SELECT a, b FROM cte
UNION
SELECT a, b FROM t
UNION
SELECT b, a FROM t
But that doesn't do the trick, unfortunately.
The desired result should be
| a | b |
|---|---|
| x | y |
| y | x |
| y | z |
| z | y |
| m | n |
| m | z |
| n | m |
| z | m |
| x | z |
| z | x |
| x | m |
| m | x |
| x | n |
| n | x |
| y | m |
| m | y |
| y | n |
| n | y |
Is there a SQL-gifted buddy out there who can help me here, please?
Thanks.
You can use recursive CTEs, but you need a list of already visited nodes. You can implement that using a string:
with cte as (
select a, b, cast('{' + a + '}{' + b + '}' as varchar(max)) as visited
from t
union all
select cte.a, t.b,
(visited + '{' + t.b + '}')
from cte join
t
on cte.b = t.a
where cte.visited not like '%{' + t.b + '}%'
)
select distinct a, b
from cte;
Note:
The above follows the directed links in the graph. If you want undirected links, then include both:
with t as (
select a, b from yourtable
union
select b, a from yourtable
),
The rest of the logic follows using t.

SQL Transposing columns to rows

I'm attempting to transpose a column of text and values to row headers. I've researched the PIVOT and UNPIVOT function but this function relies on aggregation from what I've gathered. Below is what I'm interested in achieving.
Source Table Schema:
[ID] [Category] [TextName]
1 A u
1 B v
1 C w
2 A x
2 B y
2 C z
Resulting transpose:
[ID] [A] [B] [C]
1 u v w
2 x y z
Is this possible?
SELECT id,
MIN( CASE WHEN Category = 'A' THEN TextName END ) AS A,
MIN( CASE WHEN Category = 'B' THEN TextName END ) AS B,
MIN( CASE WHEN Category = 'C' THEN TextName END ) AS C
FROM Table
GROUP BY id;
This is still a kind of aggregation even that we have a single value per cell (row-column combination).
Min/Max will give you the desired values since any basic type including strings have definition of Min/Max.
select *
from t pivot (min([TextName]) for [Category] in (A,B,C)) p
+----+---+---+---+
| ID | A | B | C |
+----+---+---+---+
| 1 | u | v | w |
+----+---+---+---+
| 2 | x | y | z |
+----+---+---+---+

Hierarchy SQL server joining two different tables

I'm having a problem making a hierarchy query.
I have the following in MS SQL DB:
Table A - Orders with order code, article, qty:
OP | ART | QTY
A | X |100
B | Y |200
Table B with assembly references of articles, but articles CAN be made from other articles if there exist a child's reference (may need to go 3 levels deep):
ART | ART2 |QTY
X | U | 20
X | O | 10
X | Z | 30
Y | Q | 20
Y | W | 15
Y | E | 30
U | Z | 10
And I want to get something like this:
A.OP |LEVEL| ART | B.ART2 |QTY
A | 2 | X | Z |(100*20*10)=2000
A | 1 | X | O |(100*10) =1000
A | 1 | X | Z |(100*30) = 3000
B | 1 | Y | Q |(200*20) = 4000
B | 1 | Y | W |(200*15) = 3000
B | 1 | Y | E |(200*30) = 6000
B | 1 | Y | Z |(200*10) = 2000
I've already made one thing:
WITH X AS (
SELECT
firstlvl.ART,
1 AS LEVEL,
firstlvl.ART2,
firstlvl.QTY,
QTY AS PARENTQTY
FROM B AS firstlvl
WHERE firstlvl.ART='X'
UNION ALL
SELECT secondlevel.ART,
EL.LEVEL +1,
secondlevel.BDT_MLC,
secondlevel.ART2,
secondlevel.QTY,
EL.PARENTQTY AS PARENTQTY
FROM B AS secondlevel
INNER JOIN X AS EL
ON secondlevel.ART = EL.ART2)
SELECT * FROM X
But now I don't know how to join quantities with table A nor how to run this query for all items on the first table.
Can anyone help me please?
Many Thanks!
with AllData as
( select op as art, art as art2, qty from a
union all
select * from b),
Tree(RootLvl, Father, Child, qty, lvl) as (
select art, art, art2, qty, 0 from AllData
where art in ( 'A' , 'B')
union all
select C.RootLvl, C.Child, AllData.art2, AllData.qty * c.qty, C.lvl + 1 from Tree C
join AllData
on C.Child = AllData.art
)
select C1.RootLvl as OP, C1.Lvl, C1.Child, C1.Qty from Tree c1
left join Tree c2
on c1.child = c2.father and
c1.rootLvl = c2.RootLvl
where C2.RootLvl is null
order by 1, 2 desc
SQL Fiddle demo
The A and B tables are almost the same. I made one from them to just simplify it. After that we use recursion to create tree and at the end I use left join to get only leafs from tree.