How to pivot rows without grouping, counting, averaging - sql

I am reworking some tables from a screwed up database. A few of the tables had the same data with different table names, and each one of them also had similar data but different column names. Anyway, this is a weird request but this has to be down like this.
I need to pivot rows up to simulate one row so I can create one record from two different tables.
I have attached a photo. The table on the left will pull a single row and the table on the left will supply 1 - n rows based on the id from the left table. I need to pivot the rows up to simulate one row and create one record with the two results.
From my checking online the pivot seems to be the way to go but it seems to want me to group or do some type of aggregating.
What is the best way to go about doing this?
table1 ---Produces one row
table1id | col1 | col2 | col3
1 Wow Wee Zee
table2 ---Produces 1 - n rows
table2id | table1id | col1 | col2 | col3
1 1 sock cloth sup
2 1 bal baa zak
3 1 x y fooZ
needs to look like this (the below is not column names, they're the result set)
Woo,wee,zee,sock,cloth,sup,bla,baaa,zak,x,y,fooZ

If using MySQL:
SELECT a.table1id, GROUP_CONCAT(a.col) AS col_values
FROM
(
SELECT table1id, col1 col FROM table1 UNION ALL
SELECT table1id, col2 FROM table1 UNION ALL
SELECT table1id, col3 FROM table1 UNION ALL
SELECT table1id, col1 FROM table2 UNION ALL
SELECT table1id, col2 FROM table2 UNION ALL
SELECT table1id, col3 FROM table2
) a
GROUP BY a.table1id
SQLFiddle Demo
If using SQL-Server:
SELECT a.table1id, b.colnames
FROM table1 a
CROSS APPLY
(
SELECT STUFF((
SELECT ',' + aa.col
FROM
(
SELECT table1id, col1 col FROM table1 UNION ALL
SELECT table1id, col2 FROM table1 UNION ALL
SELECT table1id, col3 FROM table1 UNION ALL
SELECT table1id, col1 FROM table2 UNION ALL
SELECT table1id, col2 FROM table2 UNION ALL
SELECT table1id, col3 FROM table2
) aa
WHERE aa.table1id = a.table1id
FOR XML PATH('')
), 1, 1, '') AS colnames
) b
SQLFiddle Demo

Related

Merge into (in SQL), but ignore the duplicates

I try to merge two tables in snowflake with:
On CONCAT(tab1.column1, tab1.column2) = CONCAT(tab1.column1, tab1.column2)
The problem here is that there are duplicates. that means rows where column1 and column2 in table2 are identical. the only difference is the column timestamp. Therefore i would like to have two options: either i ignore the duplicate and take only one row (with the biggest timestamp), or distinguish again based on the timestamp. the second would be nicer
But I have no clue how to do it
Example:
Table1:
Col1 Col2 Col3 Timestamp
24 10 3 05.05.2022
34 19 2 04.05.2022
24 10 4 06.05.2022
Table2:
Col1 Col2 Col3
24 10 Null
34 19 Null
What I want to do:
MERGE INTO table1 AS dest USING
(SELECT * FROM table2) AS src
ON CONCAT(dest.col1, dest.col2) = CONCAT(src.col1, src.col2)
WHEN MATCHED THEN UPDATE
SET dest.col3 = src.col3
It feels like you want to update from TABLE1 too TABLE2 not the other way around, because as your example is there is no duplicates.
It also feels like you want to use two equi join's on col1 AND col2 not concat them together:
thus how I see your data, and the words you used, I think you should do this:
create or replace table table1(Col1 number, Col2 number, Col3 number, timestamp date);
insert into table1 values
(24, 10, 3, '2022-05-05'::date),
(34, 19, 2, '2022-05-04'::date),
(24, 10, 4, '2022-05-06'::date);
create or replace table table2(Col1 number, Col2 number, Col3 number);
insert into table2 values
(24, 10 ,Null),
(34, 19 ,Null);
MERGE INTO table2 AS d
USING (
select *
from table1
qualify row_number() over (partition by col1, col2 order by timestamp desc) = 1
) AS s
ON d.col1 = s.col1 AND d.col2 = s.col2
WHEN MATCHED THEN UPDATE
SET d.col3 = s.col3;
which runs fine:
number of rows updated
2
select * from table2;
shows it's has been updated:
COL1
COL2
COL3
24
10
4
34
19
2
but the JOIN being your way work as you have used if that is correct for your application, albeit it feels very wrong to me.
MERGE INTO table2 AS d
USING (
select *
from table1
qualify row_number() over (partition by col1, col2 order by timestamp desc) = 1
) AS s
ON concat(d.col1, d.col2) = concat(s.col1, s.col2)
WHEN MATCHED THEN UPDATE
SET d.col3 = s.col3;
This is it:
WITH CTE AS
(
SELECT *,
RANK() OVER (PARTITION BY col1,col2
ORDER BY Timestamp desc) AS rn
FROM table1
)
UPDATE CTE
SET col3 = (select col3 from table2 where CONCAT(table2.col1,table2.col2) = CONCAT(CTE.col1, CTE.col2))
where CTE.rn =1;

Need two rows after join from single row based on two columns

I have a table1 with three columns and a table2 with single column.
If the value of first column is Y then I need a particular value from table 2 as a row in another table after join and if the second column is Y then I need a particular value from table 2 as another row in 3rd table after join. There is no common column in both the tables.
If two columns are in a row have Y as value then I need two rows in the final table after join. I'm using case right now for joining, but only one column is getting checked.
Can someone help me with this?
table1
--------------------
col1 col2 col3(pk)
--------------------
y n 123
y y 456
table2
--------------------
col1
--------------------
col1Y
col2Y
Expected output
table1
--------------------
col1 col2
--------------------
123 col1Y
456 col1Y
456 col2Y
select col3 as col1, 'col1y' as col2 from myTable where col1 = 'y'
union
select col3 as col1, 'col2y' as col2 from myTable where col2 = 'y'
--order by col1, col2;
SQLFiddle sample
you also can check how to transpose tables with pivot command
SQL transpose full table
We can unpivot and join to get the results you're looking for:
declare #table1 table (col1 char(1),col2 char(1),col3 int)
insert into #table1(col1,col2,col3) values
('y','n',123) ,
('y','y',456)
declare #table2 table (col1 char(5))
insert into #table2 (col1) values
('col1Y'),('col2Y')
select
u.col3 as col2,t2.col1 as col2
from
#table1 t1
unpivot
(cval for cname in (col1,col2)) u
cross apply
(select cname + cval as Complete) v
inner join
#table2 t2
on
v.complete = t2.col1
Result:
col1 col2
----------- -----
123 col1Y
456 col1Y
456 col2Y
But after the unpivot and cross apply, we didn't really need table2 at all (we could have just filtered down to rows where cval is Y). But for now I've included it in case I'm missing something or there's more to build up in the query.
Not sure if you need table2 but here is where you could do it with case statement.
SELECT col1, col2 from (
SELECT
CASE col1
WHEN 'y' THEN col3
ELSE 'null'
END AS col1,
CASE col1
WHEN 'y' THEN 'col1Y'
ELSE 'null'
END AS col2
from table1 as tbl1
union all
select
CASE col2
WHEN 'y' THEN col3
ELSE 'null'
END AS col1,
CASE col2
WHEN 'y' THEN 'col2Y'
ELSE 'null'
END AS col2
FROM table1 as tbl2) as tbl
where tbl.col1 <> 'null';
SQL Fiddle Sample

SQL move data from rows to cols

Sorry for the bad title - I simply do not know what to call the thing I want to do.
Here it goes:
In MS SQL Server 2008
I have a temp table with 4000+ rows created with the WITH statement looking like this:
ID (varchar) DATE (int)
AB1135000097 | 20151221
AB1135000097 | 20160119
AB1135000097 | 20160219
AB1135001989 | 20120223
AB1135001989 | 20120323
AB1135001989 | 20120423
.
.
.
I want to pair the data in date-ranges based on DATE.
AB1135000097 | 20151221 | 20160119
AB1135000097 | 20160119 | 20160219
AB1135001989 | 20120223 | 20120323
AB1135001989 | 20120323 | 20120423
Does this action have a name ? (I will add tags to the post when I know what I'm asking for)
Assumed schema
I am assuming that your table is like:
CREATE TABLE "TABLE"
(
tag CHAR(1) NOT NULL,
value INTEGER NOT NULL,
PRIMARY KEY(tag, value)
);
I really shouldn't have to guess the schema though.
Possible answer
Superficially, you might be after:
SELECT t1.tag, t1.value, t2.value
FROM "TABLE" AS t1
JOIN "TABLE" AS t2
ON t1.tag = t2.tag AND t2.value = t1.value + 1
ORDER BY t1.tag, t1.value;
This joins the table with itself, combining rows where the tag column values (A, B, ...) are the same, and where the value column in one row is one more than the value column in the other.
On the other hand, if you add a row ('A', 5) to the table and expect it to appear in the output as part of a row ('A', 3, 5), then the query is much harder to write without using OLAP features.
if you are using Oracle database then you can refer following query to solve this question -
with t as
(
SELECT 'A' Col1, 1 Col2
FROM Dual
UNION ALL
SELECT 'A' Col1, 2 Col2
FROM Dual
UNION ALL
SELECT 'A' Col1, 3 Col2
FROM Dual
UNION ALL
SELECT 'B' Col1, 4 Col2
FROM Dual
UNION ALL
SELECT 'B' Col1, 5 Col2
FROM Dual
UNION ALL
SELECT 'B' Col1, 6 Col2 FROM Dual
)
SELECT *
FROM (SELECT Col1,
Col2,
Lead(Col1) Over(ORDER BY Col1, Col2) Col3,
Lead(Col2) Over(ORDER BY Col1, Col2) Col4
FROM t --(your table name)
ORDER BY Col1, Col2)
WHERE Col1 = Col3
as I don't have your table name and table structure I have created one temp table in Query itself.
you need to change From t to From with your table name . .. please change col1 and col2 column name also accordingly.
I found a solution to my problem. Inspired by Jonathan Leffler's solution. Thanks a lot!
It is based on adding row-numbers to the table ordered by ID and DATE, and then self-join with ROW+1 to get the next date as a second date column.
with
SCHEDULE as
( -- remove duplicates and NULL entries
select DISTINCT ID, DATE from TABLE1
where DATE IS NOT NULL
),
SCHEDULE_WITH_ROW as
(
select * from (
select DISTINCT ROW_NUMBER()
OVER (ORDER BY ID, DATE) AS
ROW, ID, DATE
from SCHEDULE) AS SCHED
)
select
S1.ID
, S1.DATE
, S2.DATE
from SCHEDULE_WITH_ROW S1
join SCHEDULE_WITH_ROW S2 on S2.ID = S1.ID and S1.ROW + 1 = S2.ROW

SQL JOIN 3 tables, unique rows, calculation across tables

I have 3 tables. They have the same columns. I need to merge them into one table, such that I only have unique rows, the amount columns needs to be computed across the 3 tables.
e.g.
Table 1
Name1, 2, 100.00
Name5, 3, 25.00
Table 2
Name1, 2, 50.00
Table 3
Name1, 2, 60.00
Desired Result:
Name1, 2, 90.00 i.e. calculated as (100-60+50)
Name5, 3, 25.00
Any ideas? I've tried union but that doesn't calculate for me or show unique rows....
In this solution, I simply took the Min value of the second column since you did not specify how it should be combined across the three tables.
Select Z.Name, Min( SomeInt ) As MinSomeInt
, Sum( SomeDecimal ) As TotalSomeDecimal
From (
Select Name, SomeInt, SomeDecimal
From Table1
Union All
Select Name, SomeInt, SomeDecimal
From Table2
Union All
Select Name, SomeInt, SomeDecimal * -1
From Table3
) As Z
Group By Z.Name
Pretty clear question. Use UNION ALL to combine the tables into one queryable thing, then use GROUP BY to combine rows that share a value.
SELECT Col1, SUM(Col2) as Col2
FROM
(
SELECT Col1, Col2
FROM Table1
UNION ALL
SELECT Col1, Col2
FROM Table2
UNION ALL
SELECT Col1, Col2
FROM Table3
) as sub
GROUP BY Col1

SQL query to select records from three Tables seperatly

SQL query which select the record from three tables and there is no relation between these tables. Actually I want to make it a VIEW.
suppose there are three tales Table1, Table2, Table3
I want to show records of Table1 first with some filter criteria
and then the records from Table2
and in last from Table3 as when we execute the view it show like the records like a Table.
There can be any number of rows but the records must be in this sequence.
I would suggest using UNION ALL instead of union if you want all the records from each of the tables. UNION will use a distinct to filter out duplicates. If you don't need tht it is just slowing down the query.
A further explanation here:
http://wiki.lessthandot.com/index.php/Union_All
To show you how to handle when you don't have all the columns in each table:
select
1 as seq,col1, col2, col3, cast(null as varchar (40)) as col4
FROM Table1
where ...
UNION ALL
select
2 as seq,'Unknown', col2, null, col4
FROM Table2
where ...
UNION ALL
select
3 as seq ,col1, col2, col3, cast(null as varchar (40)) as col4
FROM Table3
where ...
ORDER BY seq
try:
select
1,col1, col2, col3
FROM Table1
where ...
UNION ALL
select
2,col1, col2, col3
FROM Table2
where ...
UNION ALL
select
3,col1, col2, col3
FROM Table3
where ...
ORDER BY 1
please note that each of the three queries needs to have the same number of columns and that the data types should be consistent also. Also, I used UNION ALL to speed up the query, since there is no use eliminating duplicates between the three queries because the sequence table will guarantee no dups.
to not have the sequence column in the result set try:
SELECT
col1,col2,col3
FROM (select
1 as seq,col1, col2, col3
FROM Table1
where ...
UNION ALL
select
2 as seq,col1, col2, col3
FROM Table2
where ...
UNION ALL
select
3 as seq,col1, col2, col3
FROM Table3
where ...
) dt
ORDER BY seq
you can use a UNION query:
SELECT Field1, Field2, Field3, '1' as Sequence FROM Table1 WHERE SomeCriteria
UNION
SELECT Field7, Field5, Field6, '2' FROM Table2 WHERE SomeCriteria
UNION
SELECT Field4, Field8, Field9, '3' FROM Table3 WHERE SomeCriteria
How about:
create view AZ_VIEW as
select 1 as orderby, tbl1Col1 as col1, tbl1Col2 as col2, tbl1col3 as col3 from Table1 where criteria1='val'
union
select 2, tbl2Col1, tbl2Col2, tbl2col3 from Table2 where criteria2='anotherval'
union
select 3, tbl3Col1, tbl3Col2, tbl3col3 from Table3 where criteria3='athirdval'
;
If your tables share the same columns, you can use Union All:
Select col1, col2, 1 As seq
From table1
Union All
Select col1, col2, 2 As seq
From table1
Union All
Select col1, col2, 3 As seq
From table1
Order By seq
You can UNION the three tables, taking care to ensure that they all return the same number of fields. There is a simple cheat to control the order (seen below):
SELECT * FROM
(
SELECT a, b, c, 1 as ListOrder FROM table1
UNION
SELECT a, b, c, 2 as ListOrder FROM table2
UNION
SELECT a, b, c, 3 as ListOrder FROM table3
)
ORDER BY ListOrder
You can do something like this - WHERE ID = 34 is just a sample filter:
create view vAllRecords as
select 1 as Rank, Field1, Field2 from Table1 where ID = 34
UNION
select 2 as Rank, Field1, Field2 from Table2
UNION
select 3 as Rank, Field1, Field2 from Table3
The use of UNION will remove any duplicates. If you know there will be no duplicates, or you want to see them, the query will run faster with UNION ALL instead.
ORDER BY is not allowed in views, so you'll need to order by Rank when you select from the view:
select *
from vAllRecords
order by Rank