Get every unique pair combination of a column in SQL - sql

Lets say I have given table:
1 A
2 A
3 A
How do I JOIN / combine the table with itself so I get every possible unique pair combination of the first column:
1 1 A
1 2 A
1 3 A
2 1 A
2 2 A
2 3 A
...

You can do something like this.
Cross JOIN is used for cross product
-- create
CREATE TABLE EMPLOYEE (
empId INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
-- insert
INSERT INTO EMPLOYEE VALUES (0001, 'Clark');
INSERT INTO EMPLOYEE VALUES (0002, 'Dave');
INSERT INTO EMPLOYEE VALUES (0003, 'Ava');
-- fetch
SELECT e1.empId, e2.empId, e1.name FROM EMPLOYEE e1
CROSS JOIN EMPLOYEE e2;

Related

Returning value for all rows with same key, based on a single value

Is it possible to write a SQL script to create a table, which returns a single value from a table, based on an identifier for all connected rows?
For me to explain better, here's how the data looks like:
ID
Value
QuestionID
QuestionText
1
Jim Andersson
1
Name
1
Q894556
2
Order Number
1
21-03-2022
3
Date
...
...
...
...
I would like to be able to pinpoint both the Name and the Order Number for 2 new columns like below, which should be returned for all rows connected to ID = 1:
ID
Value
QuestionID
QuestionText
Name
Order Number
1
Jim Andersson
1
Name
Jim Andersson
Q894556
1
Q894556
2
Order Number
Jim Andersson
Q894556
1
21-03-2022
3
Date
Jim Andersson
Q894556
...
...
...
...
...
...
One way of doing it is joining table on itself given that the granulation of the output table should be the same as input table.
--create table for demonstration
create or replace TEMPORARY table test1.dummy (
ID int,
Value text,
questionID int,
questionText varchar);
--populate table with given data
INSERT INTO dummy values
(1, 'Jim Andersson',1, 'Name'),
(1, 'Q894556',2,'Order Number'),
(1, '21-03-2022',3,'Date');
The idea here is that we just need to limit extra tables given the value you want to add. And since we're joining on itself we can do this using INNER JOIN since it's faster. However, if you're unsure that batch of records will all contain Name, Order Number and date you could also do this using LEFT JOIN and have those values empty.
SELECT d1.*, d2.value AS NAME, d3.value AS Order_number
FROM dummy d1
inner JOIN dummy d2 ON d1.id = d2.id AND d2.questionText = 'Name'
inner JOIN dummy d3 ON d1.id = d3.id AND d3.questionText = 'Order Number';
Now all you need to do is use this query or create new table and fill it with given query.

SQL Select Where Opposite Match Does Not Exist

Trying to compare between two columns and check if there are no records that exist with the reversal between those two columns. Other Words looking for instances where 1-> 3 exists but 3->1 does not exist. If 1->2 and 2->1 exists we will still consider 1 to be part of the results.
Table = Betweens
start_id | end_id
1 | 2
2 | 1
1 | 3
1 would be added since it is a start to an end with no opposite present of 3,1. Though it did not get added until the 3rd entry since 1 and 2 had an opposite.
So, eventually it will just return names where the reversal does not exist.
I then want to join another table where the number from the previous problem has its name installed on it.
Table = Names
id | name
1 | Mars
2 | Earth
3 | Jupiter
So results will just be the names of those that don't have an opposite.
You can use a not exists condition:
select t1.start_id, t1.end_id
from the_table t1
where not exists (select *
from the_table t2
where t2.end_id = t1.start_id
and t2.start_id = t1.end_id);
I'm not sure about your data volume, so with your ask, below query will supply desired result for you in Sql Server.
create table TableBetweens
(start_id INT,
end_id INT
)
INSERT INTO TableBetweens VALUES(1,2)
INSERT INTO TableBetweens VALUES(2,1)
INSERT INTO TableBetweens VALUES(1,3)
create table TableNames
(id INT,
NAME VARCHAR(50)
)
INSERT INTO TableNames VALUES(1,'Mars')
INSERT INTO TableNames VALUES(2,'Earth')
INSERT INTO TableNames VALUES(3,'Jupiter')
SELECT *
FROM TableNames c
WHERE c.id IN (
SELECT nameid1.nameid
FROM (SELECT a.start_id, a.end_id
FROM TableBetweens a
LEFT JOIN TableBetweens b
ON CONCAT(a.start_id,a.end_id) = CONCAT(b.end_id,b.start_id)
WHERE b.end_id IS NULL
AND b.start_id IS NULL) filterData
UNPIVOT
(
nameid
FOR id IN (filterData.start_id,filterData.end_id)
) AS nameid1
)

How to select last insert value for specific column

I have a two tables and details are give below:
create table pbc(
id number(5) primary key,
name varchar2(15));
insert into pbc values(2,'product1');
insert into pbc values(3,'product1');
insert into pbc values(4,'product1');
insert into pbc values(5,'product1');
insert into pbc values(6,'product1');
insert into pbc values(7,'product1');
and the other table is
create table zxy(
id number(5),
price number(10));
alter table zxy add(constraint zxyid_fk FOREIGN KEY (id) references pbc(id));
insert into zxy values(2,67);
insert into zxy values(3,34);
insert into zxy values(3,21);
insert into zxy values(4,65);
insert into zxy values(5,32);
insert into zxy values(5,23);
insert into zxy values(5,10);
second table select data are given below
Id price
2 67
3 34
3 21
4 65
5 32
5 23
5 10
now i have to select last inserting values such as
id price
2 67
3 21
4 65
5 10
I do not want to max price I want to last insert price
There is no way to say which value was inserted last. For ID 3 there are two prices 34 and 21, but nothing to indicate when the records got inserted. Data in tables has no inherent order; the records are considered unordered.
You need a date or something to indicate insert order.
If the table already exists this way, you are lost, because you cannot know which values are current and which are out-dated. If this is a new table and you only plan to fill it later, then add a date and a trigger to fill the date with sysdate on insert.
Based on the requirements, I don't see any usage of the first table. Try:
SELECT Z.ID, B.PRICE
FROM
(
SELECT A.ID, MAX(A.RNUM) AS LAST_INSERTED
FROM
(SELECT ID, PRICE, ROW_NUMBER() OVER (PARTITION BY ID) AS RNUM FROM ZXY) A
GROUP BY A.ID
) Z
INNER JOIN
(SELECT ID, PRICE, ROW_NUMBER() OVER (PARTITION BY ID) AS RNUM FROM ZXY) B
ON Z.ID = B.ID AND Z.LAST_INSERTED = B.RNUM;

Join all rows in table with first matched row in other table [duplicate]

This question already has answers here:
SQL join to correlated subquery where tables are related by overlapping ranges
(2 answers)
Closed 8 years ago.
I have 2 tables, and i want table1 left join table2, idea is to show all table1's rows and for each table1's row, i search records in all table2 until the 1st matched value.
So results' row number = talbe1's row number, just add table2's 1st matched value, but here i get results' row number > talbe1's row number
It depends on your table structures and how you join them. I can think of an example that the row number of the result > table 1 row number.
create table staff (
staff_id int,
name varchar(100)
)
;
create table stationery (
s_id int,
name varchar(100),
staff_id int
)
;
insert into staff values (1, 'Peter');
insert into staff values (2, 'Sally');
insert into stationery values (1, 'ruler', 1);
insert into stationery values (2, 'pencil', 1);
insert into stationery values (3, 'pencil', 2);
select *
from staff s1
left join stationery s2 on s1.staff_id = s2.staff_id ;
STAFF_ID NAME S_ID
1 Peter 11 Peter 22 Sally 3

disaggregate summarised table in SQL Server 2008

I've received data from an external source, which is in a summarised format. I need a way to disaggregate this to fit into a system I am using.
To illustrate, suppose the data I received looks like this:
receivedTable:
Age Gender Count
40 M 3
41 M 2
I want this is a disaggregated format like this:
systemTable:
ID Age Gender
1 40 M
2 40 M
3 40 M
4 41 M
5 41 M
Thanks
Karl
Depending of the range of your count you could use a lookup table that holds exactly x records for each integer x. Like this:
create table counter(num int)
insert into counter select 1
insert into counter select 2
insert into counter select 2
insert into counter select 3
insert into counter select 3
insert into counter select 3
insert into counter select 4
insert into counter select 4
insert into counter select 4
insert into counter select 4
then join with this table:
create table source(age int, gender char(1), num int)
insert into source select 40, 'm', 3
insert into source select 30, 'f', 2
insert into source select 20, 'm', 1
--insert into destination(age, gender)
select age, gender
from source
inner join counter on counter.num = source.num
From the "Works on my machine (TM)" stable a recursive query, with all the usual caveats about maximum recursion depth.
with Expanded(exAge, exGender, exRowIndex) as
(
select
Age as exAge,
Gender as exGender,
1 as exRowIndex
from
tblTest1
union all
select
exAge,
exGender,
exRowIndex+1
from
tblTest1 t1
inner join
Expanded e on (e.exAge = t1.Age and e.exGender = t1.Gender and e.exRowIndex < t1.Count)
)
select
exAge,
exGender,
exRowIndex
from
Expanded
order by
exAge,
exGender,
exRowIndex
option (MAXRECURSION 0) -- BE CAREFUL!!
You don't get the row identifier - but inserting the result of the query into a table with an identity column would deal with that.