I have 2 tables
Table 1
A | B | C | D | E | F
a Mi 2 1 4 001
b Ma 3 1 4 001
c NA 1 1 4 001
b Na 3 1 4 001
d Na 2 1 4 001
a Mi 2 1 4 002
b Na 3 1 4 002
c Ma 1 1 4 002
d Na 2 1 4 001
Table 2
A | B | C | D | E
a Mi 2 1 4
b Ma 3 1 4
c NA 1 1 4
d Na 2 1 4
OutPut :
F | D
001 1
So columns A, B, C, D, E and F are all columns that specific conditions in them. Table 1 is the table with data that needs to be compare to data in table2. If all records in different columns except F match from Table1 to the records in Table2, only those records should be selected in the output.
Only 001 from column F is displayed because it has all the 4 rows with the same values in the same columns as given in Table 2. Records with value 002 in column F are not selected because they do not have all the rows in table 2. They do have all 4 rows but the record with b does not have all the same matching values.
The final result need not be the output i have mentioned. It could just be all those rows that match the rows given in Table 2. The output is just what the last step is . I can achieve that if i get all rows that match all the records in table 2 like by like.
Something I tried-
select count(A) over(Partition by A,B,C,D,E,F) as rw,*
into #temp1
from Table1
select sum(rw) as sm, F
from #temp1 group by F
select F
from #temp
where sm = (select count(A) from Table2)
One of the issues with this logic is that 002 can have 2-3 duplicated rows which might result in the count being equal to the count of rows in table2 .
With a join of the tables and then group by F:
select t1.f, max(t1.d) d
from table2 t2 inner join (select distinct * from table1) t1
on t1.A = t2.A and t1.B = t2.B and t1.C = t2.C and t1.D = t2.D and t1.E = t2.E
group by t1.f
having count(*) = (select count(*) from table2)
I used max(t1.d) as it is not clear if the value of D is the same for each F.
See the demo.
Results:
> f | d
> :-- | -:
> 001 | 1
If you want the rows from table1 that match the rows from table2, use a CTE:
with cte as (
select t1.f
from table2 t2 inner join (select distinct * from table1) t1
on t1.A = t2.A and t1.B = t2.B and t1.C = t2.C and t1.D = t2.D and t1.E = t2.E
group by t1.f
having count(*) = (select count(*) from table2)
)
select t1.* from table1 t1
where
t1.f in (select f from cte)
and exists (
select 1 from table2 t2
where t1.A = t2.A and t1.B = t2.B and t1.C = t2.C and t1.D = t2.D and t1.E = t2.E
)
See the demo.
Results:
> A | B | C | D | E | F
> :- | :- | -: | -: | -: | :--
> a | Mi | 2 | 1 | 4 | 001
> b | Ma | 3 | 1 | 4 | 001
> c | NA | 1 | 1 | 4 | 001
> d | Na | 2 | 1 | 4 | 001
> d | Na | 2 | 1 | 4 | 001
If you want distinct rows use:
select distinct t1.* from table1 t1
instead.
Results:
> A | B | C | D | E | F
> :- | :- | -: | -: | -: | :--
> a | Mi | 2 | 1 | 4 | 001
> b | Ma | 3 | 1 | 4 | 001
> c | NA | 1 | 1 | 4 | 001
> d | Na | 2 | 1 | 4 | 001
Disregarding the suspect row I mention in the comment, I think this is what you want:
select *
from [Table 1] t1
where exists
(
select 1
from [Table 2] t2
where
t1.A=t2.A
and t1.B=t2.B
and t1.C=t2.C
and t1.D=t2.D
and t1.E=t2.E
)
Related
I want to update one table using another table on field "Id" such that it wont create duplicates
let say my first table is Table1 and second table is Table2 . I would like to update the row in Table1 from Table2 when the Id is matching
I am aware of using UNION function but this applies to entire columns where I only need to consider a single column.
https://docs.snowflake.com/en/sql-reference/operators-query.html#union-all
Example of my Tables
Table1
Id name number value
1 a 8 100
2 b 8 100
3 c 8 100
4 d 8 100
Table2
Id name number value
3 c 8 99
4 d 6 100
5 e 7 100
Expected output
Id name number value
1 a 8 100
2 b 8 100
3 c 8 99
4 d 6 100
5 e 7 100
Please note that in the output table row with Id 3,4 has be updated and new Id 5 is inserted. Can someone help me with the select query to get the desired output?
You can use MERGE command:
merge into table1 using table2 on table1.id = table2.id
when matched then
update set table1.name = table2.name, table1.number = table2.number, table1.value = table2.value
when not matched then
insert (Id,name,number,value) values (table2.id, table2.name, table2.number, table2.value);
select * from table1;
+----+------+--------+-------+
| ID | NAME | NUMBER | VALUE |
+----+------+--------+-------+
| 5 | e | 7 | 100 |
| 1 | a | 8 | 100 |
| 2 | b | 8 | 100 |
| 3 | c | 8 | 99 |
| 4 | d | 6 | 100 |
+----+------+--------+-------+
https://docs.snowflake.com/en/sql-reference/sql/merge.html
If you don't want to update the table, you may use IFNULL and full outer join:
select
IFNULL( t1.id, t2.id) id,
IFNULL( t2.name, t1.name ) name,
IFNULL( t2.number, t1.number ) number,
IFNULL( t2.value, t1.value ) value
from table1 t1
full join table2 t2
on t1.id = t2.id;
+----+------+--------+-------+
| ID | NAME | NUMBER | VALUE |
+----+------+--------+-------+
| 1 | a | 8 | 100 |
| 2 | b | 8 | 100 |
| 3 | c | 8 | 99 |
| 4 | d | 6 | 100 |
| 5 | e | 7 | 100 |
+----+------+--------+-------+
In SQL server, I have the following tables (they are simplified):
Table A:
ID| NAME | ID_STATUS | STATUS
--------------------------------
1 | One | 1 | Confirmed
2 | Two | 2 | Pending
3 | Three| 0 | Deleted
4 | Four | 1 | Confirmed
Table B (Is a Detailed from A):
ID (same from A) | NAME | ID_STATUS | STATUS
-----------------------------------------------
1 | One | 1 | Confirmed
1 | One | 1 | Confirmed
2 | Two | 2 | Pending
3 | Three| 2 | Pending
3 | Three| 2 | Pending
4 | Four | 2 | Pending
I need get distinct rows of (ID, NAME, ID_STATUS, STATUS) from A, which have (ID_STATUS, STATUS) different from B
Expected result:
ID | NAME | ID_STATUS | STATUS
---------------------------------
3 | Three| 0 | Deleted
4 | Four | 1 | Confirmed
I'm trying by a LEFT OUTER JOIN without success… (return 0 results)
select A.ID, A.NAME, A.ID_STATUS, A.STATUS from A left outer join B
on A.ID = B.ID
where
A.ID_STATUS != B.ID_STATUS
select A.ID, A.NAME, A.ID_STATUS, A.STATUS
from A
left outer join B
on A.ID = B.ID
and A.ID_STATUS = B.ID_STATUS
where b.ID is null
select A.ID, A.NAME, A.ID_STATUS, A.Acol from A left outer join B on A.ID = B.ID and A.ID_STATUS = B.ID_STATUS where B.ID is null;
lI am trying to flatten/combine rows from a table with a parent-child hierarchy. I'm trying to identify the beginning and the end of each 'link' - so if a is linked to b, b is linked to c, and then c is linked to d, I want the output to link a to d.
I'm trying my best to avoid using a procedure with loops, so any advice would be much appreciated!
The original dataset and the required output is as follows:
personID | form | linkedform
---------|---------|---------
1 | a | b
1 | b | c
1 | c | d
1 | d | NULL
2 | e | f
2 | f | g
2 | g | NULL
2 | h | i
2 | i | NULL
3 | j | NULL
3 | k | l
3 | l | NULL
Desired output:
personID | form | linkedform
---------|---------|---------
1 | a | d
2 | e | g
2 | h | i
3 | j | NULL
3 | k | l
Each personID can have multiple links, and a link can be made of just one or multiple forms.
-- use a recursive cte to build the hierarchy
-- start with [linkedform] = null and work your way up
;WITH cte AS
(
SELECT *, [form] AS [root],
1 AS [Level]
FROM Table1
WHERE [linkedform] IS NULL
UNION ALL
SELECT t1.*,
[root],
[Level] + 1
FROM Table1 t1
JOIN cte ON cte.form = t1.linkedform
)
-- level 1 will be the last element, use row_number to get the first element
-- join the two together based on last and first level, that have the same personid and root ([linkedform] = null)
SELECT cte.personId,
cte2.form,
cte.form
FROM cte
JOIN ( SELECT *,
ROW_NUMBER() OVER (PARTITION BY personId, [root] ORDER BY Level DESC) Rn
FROM cte) cte2
ON cte2.Rn = cte.Level
AND cte2.personId = cte.personId
AND cte2.root = cte.root
WHERE cte.[Level] = 1
ORDER BY cte.personId, cte2.form
I have question about SQL Server
Source: emp
id | name | check |deptname
100 | a | 1 |ceo
100 | b | 2 |hr
100 | c | 3 |po
100 | d | 5 |no
101 | a | 1 |pm
101 | b | 5 |ceo
102 | a | 1 |rn
102 | b | 2 |han
Here same id have check 2 and 5 values then we need to replace check values to 2 check values for that id.
Based on above table I want load/output data into target table like below
Target : emp1
id | name | check |deptname
100 | a | 1 |ceo
100 | d | 2 |hr
100 | c | 3 |po
101 | a | 1 |pm
101 | b | 5 |ceo
102 | a | 1 |rn
102 | b | 2 |han
and I tried like below
select
a1.id,
a1.name,
isnull(a2.[check],a1.[check]) as [check]
from
emp as a1
left outer join
emp as a2 on a2.id = a1.id
and a1.[check] in (2,5)
and a2.[check] in (2,5)
and a2.[check] <> a1.[check]
where
a2.id is null
or (a1.[check] = 5
and a2.[check] = 2)
That query does not return the right result.
Please tell me how to write query to get the expected output in SQL Server
This is how you can do that:
select
e1.id,
isnull(e2.name, e1.name) as name,
e1.[check],
e1.deptname
from emp e1
left outer join emp e2
on e2.id = e1.id and e1.[check] = 2 and e2.[check] = 5
where
not exists (select 1 from emp e3 where e3.id = e1.id and
e1.[check] = 5 and e3.[check] = 2)
Example in SQL Fiddle
Basically, I'll have to group the people in Table 2 according to departments (known only through referring to table 1) and then sum each department according to type (known through Table 2). The results have to grouped by departments (known through table 1).
Can anyone help me execute such an action in SQL?
Sample data:
Table 1
DeptID | Dept
1 | Eng
2 | Mkt
3 | Mkt
4 | Eng
Table 2
Person | DeptID | Type | Amount
A | 1 | p1 | 5
B | 2 | p2 | 3
C | 3 | p1 | 10
D | 2 | p1 | 20
E | 4 | p2 | 17
F | 1 | p2 | 15
G | 2 | p1 | 16
Table Results
Dept | Sum p1 | Sum p2
Eng | 5 | 32
Mkt | 46 | 3
You could do this using conditional aggregation.
SELECT
t1.Dept,
[Sum p1] = SUM(CASE WHEN t2.Type = 'p1' THEN t2.Amount END),
[Sum p2] = SUM(CASE WHEN t2.Type = 'p2' THEN t2.Amount END)
FROM Table2 t2
INNER JOIN Table1 t1
ON t1.DeptID = t2.DeptID
GROUP BY
t1.Dept