Select id with unique value - sql

+----+--------+-----------+
| ID | ID_DEP | OPERATION |
+----+--------+-----------+
| 1 | 2 | T1 |
| 2 | 2 | T1 |
| 3 | 2 | T4 |
| 4 | 1 | T1 |
| 5 | 1 | T1 |
| 6 | 1 | T4 |
| 7 | 4 | T6 |
| 8 | 3 | T1 |
| 9 | 3 | T1 |
| 10 | 5 | T9 |
+----+--------+-----------+
Hey guys, help me with that simple question.
How to select only these id's (ID_DEP) that have ONLY T1 from Operation column and not other value.

I'd use a WHERE NOT EXISTS
Test Data
IF OBJECT_ID('tempdb..#TestData') IS NOT NULL DROP TABLE #TestData
CREATE TABLE #TestData (ID int, ID_DEP int, OPERATION varchar(2))
INSERT INTO #TestData (ID, ID_DEP, OPERATION)
VALUES
(1,2,'T1')
,(2,2,'T1')
,(3,2,'T4')
,(4,1,'T1')
,(5,1,'T1')
,(6,1,'T4')
,(7,4,'T6')
,(8,3,'T1')
,(9,3,'T1')
,(10,5,'T9')
Query
SELECT
td.*
FROM #TestData td
WHERE NOT EXISTS (SELECT 1 FROM #TestData sub WHERE sub.OPERATION <> 'T1' AND td.ID_DEP = sub.ID_DEP)
Output
ID ID_DEP OPERATION
8 3 T1
9 3 T1
Basically, the NOT EXISTS returns any rows where the value IS NOT 'T1'. If an ID_DEP exists then we want to exclude this from the result set.

Related

SELECT DISTINCT on multiple columns with new value

I have these two tables.
Table #1:
+----+------+-----+
| ID | Y | AGE |
+----+------+-----+
| 1 | 2022 | a |
| 1 | 2022 | b |
| 3 | 2021 | a |
| 4 | 2021 | a |
| 4 | 2021 | b |
| 4 | 2021 | c |
| 7 | 2021 | a |
| 7 | 2022 | b |
+----+-------+----+
Table #2:
+----+------+-----------+
| ID | num | something |
+----+------+-----------+
| 1 | 10 | a1221 |
| 3 | 30 | a4342 |
| 4 | 40 | bdssd |
| 7 | 70 | asdsds |
+----+-----+------------+
and I would like to merge them into this result set:
+----+-------+-----+
| ID | Y | num |
+----+-------+-----+
| 1 | 2022 | 10 |
| 3 | 2021 | 30 |
| 4 | 2021 | 40 |
| 7 | 2021 | 70 |
| 7 | 2022 | 70 |
+----+-------+-----+
That means I would like take unique pairs of T1.ID and T1.Y ignoring column AGE and them INNER JOIN resulting table with T2 on T1.ID = T2.ID.
I know I can do this in steps as
WITH cte AS
(
SELECT ID, Y
FROM T1
GROUP BY ID, Y
)
SELECT cte.ID, cte.Y, T2.num
FROM cte
INNER JOIN T2 ON cte.ID = T2.ID
but is there any better way without creating a temporary table? Because simple
SELECT T1.ID, T1.Y, T2.num
FROM T1
INNER JOIN T2 ON T1.ID = T2.ID
will result with duplicates that comes from T1.AGE even tho I'm not using it
I think it's better to use views for this:
CREATE VIEW dbo.view1
AS
SELECT
ID
,Y
FROM T1
GROUP BY ID
,Y
GO
And call it wherever needed like tables:
SELECT v1.ID, v1.Y, T2.num
FROM view1 v1
INNER JOIN T2 ON v1.ID = T2.ID

Oracle SQL - Mapping attributes from two tables

I have two tables T1 and T2.
T1 -> Contains the main data
T2 -> Configuration table
T1:
FILE | ATTRB1 | ATTRB2 | ATTRB3 | ATTRB4 |
F1 | 0 | 2 | 4 | 6 |
F1 | 1 | 3 | 5 | 7 |
F2 | 7 | 8 | 9 | 0 |
F2 | 1 | 2 | 3 | 4 |
F3 | 0 | 2 | 0 | 4 |
F3 | 1 | 0 | 3 | 0 |
F4 | 3 | 6 | 9 | 0 |
F4 | 4 | 8 | 1 | 2 |
T2:
ATTRB_ID | ATTRB_NAME | COLUMN | TABLE_REF |
1 | WORDS | ATTRB1 | T1 |
2 | CHARS | ATTRB2 | T1 |
3 | MATCH | ATTRB3 | T1 |
4 | SPACES | ATTRB4 | T1 |
Note: Mapping between T1 and T2 is using COLUMN attribute and TABLE_REF. If TABLE_REF is T1 then the records in it refer to T1.
Result Table:
FILE | WORDS | CHARS | MATCH | SPACES |
F1 | 0 | 2 | 4 | 6 |
F1 | 1 | 3 | 5 | 7 |
F2 | 7 | 8 | 9 | 0 |
F2 | 1 | 2 | 3 | 4 |
F3 | 0 | 2 | 0 | 4 |
F3 | 1 | 0 | 3 | 0 |
F4 | 3 | 6 | 9 | 0 |
F4 | 4 | 8 | 1 | 2 |
How can we achieve the above result using oracle SQL?
Any help on this topic is much appreciated.
Unpivot data from T1, join with T2, pivot again:
select *
from (
select rn, file_, val, attrb_name
from (select * from (select rownum rn, t1.* from t1)
unpivot (val for attr in (ATTRB1, ATTRB2, ATTRB3, ATTRB4))) t1
left join t2 on t2.col = t1.attr)
pivot (max(val) for attrb_name in ('WORDS', 'CHARS', 'MATCH', 'SPACES'))
order by rn
dbfiddle demo
You can create a function that returns a cursor
create or replace function query2 (p_table varchar2)
return sys_refcursor
is
rf_cur sys_refcursor;
sql_stm varchar2(4000);
begin
select 'SELECT ' || listagg('"'||column_name||'"' || nvl2(attrb_name,' as "'||attrb_name||'"',''),',') within group (order by column_id) ||' FROM '||p_table into sql_stm
from user_tab_columns
left join t2 on column_name = "COLUMN"
where table_name = p_table;
dbms_output.put_line(sql_stm);
open rf_cur for sql_stm;
return rf_cur;
end query2;
Usage: select query2('T1') from dual;

Extend query to include Parent Ids

I have the following SQL statement -
SELECT
gen_id, gen_name, COUNT(*)
FROM
table
WHERE
parent_id in (1,2,3,4)
GROUP BY
gen_id, gen_name
HAVING
COUNT(*) > 1
This works a treat and brings back the following result -
+--------+----------+------------------+
| gen_id | gen_name | (No column name) |
+--------+----------+------------------+
| 1 | test1 | 2 |
| 2 | test2 | 4 |
| 6 | test6 | 2 |
| 9 | test9 | 2 |
+--------+----------+------------------+
My question being is, the only one of the above results I can determine which parents it has is test2 as it has a count for all four parent_id's. How can I modify my SQL to bring back a result set whereby I can see which parent ids belong to which gen_ids.
Results something like -
+--------+----------+-----------+
| gen_id | gen_name | parent_id |
+--------+----------+-----------+
| 1 | test1 | 1 |
| 1 | test1 | 2 |
| 2 | test2 | 1 |
| 2 | test2 | 2 |
| 2 | test2 | 3 |
| 2 | test2 | 4 |
| 6 | test6 | 3 |
| 6 | test6 | 4 |
| 9 | test9 | 2 |
| 9 | test9 | 4 |
+--------+----------+-----------+
One way to do it is using exists:
SELECT
gen_id, gen_name, parent_id
FROM
table AS t0
WHERE
parent_id in (1,2,3,4)
AND EXISTS
(
SELECT 1
FROM table AS t1
WHERE t0.gen_Id = t1.gen_id
AND t0.parent_id != t1.parent_Id
)
Another option would be to use a cte:
WITH CTE AS
(
SELECT
gen_id, gen_name, parent_id, COUNT(*) OVER(PARTITION BY gen_id) As cnt
FROM
table
WHERE
parent_id in (1,2,3,4)
)
SELECT gen_id, gen_name, parent_id
FROM CTE
WHERE cnt > 1
simple remove count and group by
SELECT
gen_id, gen_name, parent_id
FROM
table
WHERE
parent_id in (1,2,3,4)

How to update parent nodes in new branch of adjacency list table using SQL Server 2016/17?

I have adjacency list table where I need to clone set of nodes and insert it to a new branch. Basically I want to clone set of nodes having the same structure of parent nodes in new branch. I use temp table where I have source and inserted nodes. I tried to join temp table by item and use CTE but I got wrong result.
I tested this answer but it does not work if parent nodes are same for more than 1 item.
How to update parent nodes (excluding root node) in a correct way?
Is there way to update it without using of temp table?
Table
|node|parent|item|
| 1 | Null | a |
| 2 | 1 | b |
| 3 | 1 | c |
Cloned nodes
|node|parent|item|
| 4 | Null | a |
| 5 | 1 | b |
| 6 | 1 | c |
Temp table
|inserted_node|old_node|item|old_parent|
| 4 | 1 | a | Null |
| 5 | 2 | b | 1 |
| 6 | 3 | c | 1 |
Expected result
|node|parent|item|
| 1 | Null | a |
| 2 | 1 | b |
| 3 | 1 | c |
| 4 | Null | a |
| 5 | 4 | b |
| 6 | 4 | c |
Wrong result
|node|parent|item|
| 1 | Null | a |
| 2 | 1 | b |
| 3 | 1 | c |
| 4 | Null | a |
| 5 | 5 | b |
| 6 | 6 | c |
SQL Query
;WITH CTE AS
(
SELECT
t.parent AS old_parent,
t2.node AS new_parent
FROM Table t
LEFT JOIN #TempTable t2 ON t2.item = t.item
WHERE t.node IN (SELECT node FROM #TempTable ) AND t.parent IS NOT NULL
)
UPDATE CTE
SET old_parent = new_parent
I could solve it by joining temp table second time. Is there a better solution?
;WITH CTE AS
(
SELECT
t.parent AS old_parent,
t3.node AS new_parent
FROM Table t
LEFT JOIN #TempTable t2 ON t2.item = t.item
LEFT JOIN #TempTable t3 ON t2.parent = t3.old_node
WHERE t.node IN (SELECT node FROM #TempTable ) AND t2.parent IS NOT NULL
)
UPDATE CTE
SET old_parent = new_parent

Insert unique values into same table

I have a table and I want to insert old values with new date but only the unique ones .
t1
ID | Block | Flats |
1 | 1 | GF-1 |
2 | 1 | GF-2 |
3 | 2 | GF-1 |
4 | 2 | GF-2 |
5 | 2 | GF-2 |
this is part of my table with some sample data I want it to become after copy
ID | Block | Flats |
1 | 1 | GF-1 |
2 | 1 | GF-2 |
3 | 2 | GF-1 |
4 | 2 | GF-2 |
5 | 2 | GF-2 |
6 | 1 | GF-1 |
7 | 1 | GF-2 |
8 | 2 | GF-1 |
9 | 2 | GF-2 |
As after copy it only copied the distinct values and GF-2 came only once.
But when I tried
insert into t1 (ID,Block,Flats) select distinct Block,Flats from t1
It copies that GF-2 twice in block 2.
Note: ID column is incremented by 1 automatically.
You can generate all the rows using cross join, then weed out the ones that already exist:
insert into t1(block, flats)
select b.block, f.flats
from (select distinct block from t1) b cross join
(select distinct flats from t1) f left join
t1
on t1.block = b.block and t1.flats = f.flats
where t1.block is null;
Note: This assumes that id is an identity column (which is I see you have described as being the case).