SQL Compare rows of a table with multiple columns - sql

I have a table T1
Id
Col1
Col2
IsActive
1
T1
v1
1
2
T2
v2
0
Now received the following data and it need to be inserted into the above table.
| Col1 | Col2 |
|--------|--------|
| T1 | v1 |
| T2 | v2 |
| T3 | v3 |
As this data contains some duplicated values, it need to be inserted based on IsActive Column value. For row with IsActive 1, need to insert with IsActive 2 and for row with IsActive 0, need to insert with IsActive 1 like below, the unique data need to be inserted with IsActive 1 and that is not a problem right now
Id
Col1
Col2
IsActive
1
T1
v1
1
2
T2
v2
0
3
T1
v1
2
4
T2
v2
1
5
T3
v3
1
I have created a Temp table #Temp and inserted common rows in new incoming data and data from existing table like below:
#Temp
Col1
Col2
IsActive
T1
v1
1
T2
v2
0
T1
v1
NULL
T2
v2
NULL
Using Group By I can able to select duplicate rows but I need to insert based on IsActive value, so I stuck here.
insert into T1
select Col1, Col2, '1' from #Temp
GROUP BY Col1, Col2
HAVING COUNT(Col1) > 1
I need help on this above part, thanks in advance

Try this:
-- create temp table with values to be inserted
INSERT INTO #ToInsert
([Col1], [Col2])
VALUES
('T1', 'v1'),
('T2', 'v2'),
('T3', 'v3')
-- join each value of the temp table to the original table. if
-- value exists increment its `IsActive` by 1, otherwise set it to 1
INSERT INTO t (Col1, Col2, IsActive)
SELECT i.Col1, i.Col2, COALESCE(t.IsActive + 1, 1) AS IsActive
FROM #ToInsert i
LEFT JOIN (
SELECT Col1, Col2, max(IsActive) as IsActive
FROM t
GROUP BY Col1, Col2
) t ON i.Col1 = t.Col1 AND i.Col2 = t.Col2
Demo here

Related

Spliting a single column into two different columns SQL Server [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have something like this:
Column
1
2
3
4
-1
-2
-3
-4
And I wanted an output something like this:
C1 C2
1 -1
2 -2
3 -3
4 -4
Can anyone help me on writing a query to get this output in T-SQL??
and what if something is like this:
values
1
-5
10
-9
15
-3
8
-11
12
-17
and I have to make two columns that separates the positive values in one column and negative values in another.
You can use aggregation:
select max(col1), min(col1)
from t
group by abs(col1);
This will do what you want.. a simple self-join
create table test1
(
col1 int not null
)
insert into test1 (col1) values (1)
insert into test1 (col1) values (2)
insert into test1 (col1) values (3)
insert into test1 (col1) values (4)
insert into test1 (col1) values (-1)
insert into test1 (col1) values (-2)
insert into test1 (col1) values (-3)
insert into test1 (col1) values (-4)
select a.col1 C1, b.col1 C2 from test1 a
join test1 b on a.col1 = -b.col1
where a.col1 > 0
SELECT t1.col1 as C1,
t2.col1 AS C2
FROM tbl t1
JOIN tbl t2
ON t1.col1 = (t2.col1 * -1)
WHERE t1.col1 > 0
GO
C1 | C2
-: | -:
1 | -1
2 | -2
3 | -3
4 | -4
dbfiddle here
You can join the values of the two queries by using the analytic function ROW_NUMBER():
WITH A AS (
SELECT col1, ROW_NUMBER() OVER (ORDER BY col1 desc) AS row_num
FROM TABLE_1
WHERE col1 < 0),
B AS (
SELECT col1, ROW_NUMBER() OVER (ORDER BY col1) AS row_num
FROM TABLE_1
WHERE col1 >= 0)
SELECT A.col1 AS C1, B.col1 AS C2
FROM A
INNER JOIN B
ON A.row_num = B.row_num;
You have to JOIN the table with itself and then limit the result so the negative ones are excluded from the first column
SELECT t1.Col1 c1, t2.Col1 c2 FROM tbl t1
JOIN tbl t2 ON t1.Col1 = t2.Col1*-1 AND t1.Col1 > 0
Answer to second question:
The idea is to SELECT positive and negative numbers separately and then do a FULL OUTER JOIN on their row numbers.
SELECT t1.Col1 c1, t2.Col1 c2 FROM (
SELECT t11.Col1,
ROW_NUMBER() OVER(ORDER BY t11.Col1 ASC) rn
FROM tbl t11
WHERE t11.Col1 > 0
) t1 FULL JOIN (
SELECT t22.Col1,
ROW_NUMBER() OVER(ORDER BY t22.Col1 DESC) rn
FROM tbl t22
WHERE t22.Col1 < 0
) t2 ON t2.rn = t1.rn;
Example:
CREATE TABLE tbl ( Col1 int );
INSERT INTO tbl VALUES (6), (7), (-4), (1), (-2), (3), (5);
-- RESULT
| c1 | c2 |
|----|--------|
| 1 | -2 |
| 3 | -4 |
| 5 | (null) |
| 6 | (null) |
| 7 | (null) |

How to inset one table colume data into another table column

Can u help me how to insert Column A data into col3 at place of null.
See the attachment.
TABLE TAB1
--------------
col1 col2 col3
5 7 NULL
8 11 NULL
3 6 NULL
2 12 NULL
TABLE TAB2
-----------
ColA CoB
7 5
18 8
24 3
36 2
Desire Output Like
col1 col2 col3
5 7 7
8 11 18
3 6 24
2 12 36
This is called commutative sum.
1. It's work for same table.
update TABLENAME set col3=col2
**2.**For inserting one table column data into another table
INSERT into tab1(col1)
select col1 from tab2
From what I can tell, you want a cumulative sum from the second column:
with toupdate as (
select t1.*,
sum(t1.col2) over (order by ??) as cume_col2
from tab1 t1
)
update toupdate
set col3 = cume_col2;
In order to do a cumulative sum, you need a column that specifies the order for the sum. Your data as shown does not have an appropriate column.
EDIT:
Oh, I see. The ordering comes from the second table:
with toupdate as (
select t1.*,
sum(t1.col2) over (order by t2.cola) as cume_col2
from tab1 t1 join
tab2 t2
on t1.col1 = t2.colb
)
update tab1
set col3 = toupdate.cume_col2
from tab1 join
toupdate
on tab1.col1 = toupdate.col1;
Try this:
Update tab1
set Col3=tab2.ColA
from tab1
inner join tab2 on tab1.col1=tab2.colB

Get groups that are exactly equal to a table

I have a query that groups easily. I need to get the groups that have exactly the same records to another table (relationship).
I'm using ANSI-SQL under SQL Server, but I accept an answer of any implementation.
For example:
Table1:
Id | Value
---+------
1 | 1
1 | 2
1 | 3
2 | 4
3 | 2
4 | 3
Table2:
Value | ...
------+------
1 | ...
2 | ...
3 | ...
In my example, the result is:
Id |
---+
1 |
How imagined that it could be the code:
SELECT Table1.Id
FROM Table1
GROUP BY Table1.Id
HAVING ...? -- The group that has exactly the same elements of Table2
Thanks in advance!
You can try the following:
select t1.Id
from Table2 t2
join Table1 t1 on t1.value = t2.value
group by t1.Id
having count(distinct t1.value) = (select count(*) from Table2)
SQLFiddle
To get the same sets use an inner join:
SELECT Table1.Id
FROM Table1
INNER JOIN table2 ON table1.id=table2.id
GROUP BY Table1.Id
HAVING ...? --
CREATE TABLE #T1 (ID INT , [Values] INT) INSERT INTO #T1 VALUES (1,1),(1,2),(1,3),(2,4),(2,5),(3,6)
CREATE TABLE #T2 ([Values] INT) INSERT INTO #T2 VALUES (1),(2),(3),(4)
SELECT * FROM #T1
SELECT * FROM #T2
SELECT A.ID
FROM
( SELECT ID , COUNT(DISTINCT [Values]) AS Count FROM #T1
GROUP BY ID
) A
JOIN
(
SELECT T1.ID, COUNT(DISTINCT T2.[Values]) Count
FROM #T1 T1
JOIN #t2 T2
ON T1.[Values] = T2.[Values]
GROUP BY T1.ID
) B
ON A.ID = B.ID AND A.Count = B.Count

require to form a sql query

I was working on preparing a query where I was stuck.
Consider tables below:
table1
id key col1
-- --- -----
1 1 abc
2 2 d
3 3 s
4 4 xyz
table2
id col1 foreignkey
-- ---- ----------
1 12 1
2 13 1
3 14 1
4 12 2
5 13 2
Now what I need is to select only those records from table1 for which the corresponding entries in table2 does not have say col1 value as 12.
So the challenge is after applying join even though it will skip for value 1 corresponding to col1 equal to 12 it still has another multiple rows whose values are say 13, 14 for which also they have same foreignkey. Now what I want is if there is a single row having value 12 then it should not pick that id at all from table1.
How can I form a query with this?
The output which i need is say from above table structure i want to get those records from table1 for which col1 value from table2 does not have value as 14.
so my query should return me only row 2 from table1 and not row 1.
Another way of doing that. The first two queries are just for making the sample data.
;WITH t1(id ,[key] ,col1) AS
(
SELECT 1 , 1 , 'abc' UNION ALL
SELECT 2 , 2 , 'd' UNION ALL
SELECT 3 , 3 , 's' UNION ALL
SELECT 4 , 4 , 'xyz'
)
,t2(id ,col1, foreignkey) AS
(
SELECT 1 , 12 , 1 UNION ALL
SELECT 2 , 13 , 1 UNION ALL
SELECT 3 , 14 , 1 UNION ALL
SELECT 4 ,12 , 2 UNION ALL
SELECT 5 ,13 , 2
)
SELECT id, [key], col1
FROM t1
WHERE id NOT IN (SELECT t2.Id
FROM t2
INNER JOIN t1 ON t1.Id = t2.foreignkey
WHERE t2.col1 = 14)
This is a typical case for NOT EXISTS:
SELECT id, [key], col1
FROM table1 t1
WHERE NOT EXISTS (SELECT 1
FROM table2 t2
WHERE t2.foreignkey = t1.id AND t2.col1 = 14)
The above query will not select a row from table1 if there is a single correlated row in table2 having col1 = 14.
Output:
id key col1
-------------
2 2 d
3 3 s
4 4 xyz
If you want to return records that, in addition to the criterion set above, also have correlated records in table2, then you can use the following query:
SELECT t1.id, MAX(t1.[key]) AS [key], MAX(t1.col1) AS col1
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.foreignkey
GROUP BY t1.id
HAVING COUNT(CASE WHEN t2.col1 = 14 THEN 1 END) = 0
Output:
id key col1
-------------
2 2 d
You can also achieve the same result with the second query using a combination of EXISTS and NOT EXISTS:
SELECT id, [key], col1
FROM table1 t1
WHERE EXISTS (SELECT 1
FROM table2 t2
WHERE t2.foreignkey = t1.id)
AND
NOT EXISTS (SELECT 1
FROM table2 t3
WHERE t3.foreignkey = t1.id AND t3.col1 = 14)
select t1.id,t1.key,
(select ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col1 DESC) AS Row,* into
#Temp from table1)
from table1 t1
inner join table2 t2 on t1.id=t2.foreignkey
where t2.col1=(select col1 from #temp where row>1)

Trying to get my delete statement to work

I want to remove rows from a table, based on a column from another table as such:
Table1: Table2:
value value, i
If table2.i is less than 1, delete corresponding row from table1 (but keep it in table2).
The problem is that value isn't unique, so if I have this for exampe:
Table1 table2
+-------+ +-----------+
| value | | value | i |
+-------+ +-----------+
| 5 | | 5 | 0 |
| 3 | | 5 | 3 |
+-------+ | 3 | 0 |
| 3 | 0 |
+-----------+
Value 3 should be deleted from table1 (since all occurrences in table2 has i<1) but value 5 should stay(because of i=3 row in table2)
My code so far (doesn't work):
DELETE FROM Table1, Table2
WHERE (SELECT MIN(Table2.i) FROM Table1, Table2
WHERE Table1.value = Table2.value) < 1;
Problem is: since my subquery returns min for ALL rows, everything gets deleted.
And I can't use "group by" in my subquery because then my comparison isn't allowed.
Try this one:
DELETE FROM Table1
WHERE NOT EXISTS(SELECT 1
FROM Table2
WHERE Table2.i > 0
AND Table2.value = Table1.value)
I dont know why you are using min, instead u should use max:
try this
DELETE FROM Table1
WHERE Table1.value1 = Table2.value1
and (SELECT MAX(Table2.i) FROM Table2
WHERE Table1.value1 = Table2.value1) < 1;
Ok, I'd start by writing a query that selects the rows you want to delete,
SELECT
*
FROM
Table1
EXCEPT
(
SELECT
t1.value
FROM
Table1 t1
JOIN
Table2 t2
ON t2.value = t1.value
WHERE
t2.i > 0
);
See Fiddle
Then change the SELECT to a DELETE
DELETE Table1
FROM
Table1 t1
WHERE
t1.value NOT IN
(
SELECT
t1.value
FROM
Table1 t1
JOIN
Table2 t2
ON t2.value = t1.value
WHERE
t2.i > 0
);
See Fiddle
How about:
delete from table1 where value in
(select value from table2 group by value having max(i) < 1)
Grouping table 2 by value and using having to detect where the maximum is less than 1 allows you to select the correct values for deletion from table 1.
having is basically a where clause which comes into play after aggregation so can be used with max and so on.
Here's a script to show it in action:
DROP TABLE TABLE1;
DROP TABLE TABLE2;
CREATE TABLE TABLE1 (VALUE INTEGER);
CREATE TABLE TABLE2 (VALUE INTEGER, I INTEGER);
INSERT INTO TABLE1 VALUES (5);
INSERT INTO TABLE1 VALUES (3);
INSERT INTO TABLE2 VALUES (5, 0);
INSERT INTO TABLE2 VALUES (5, 3);
INSERT INTO TABLE2 VALUES (3, 0);
INSERT INTO TABLE2 VALUES (3, 0);
SELECT * FROM TABLE1;
SELECT * FROM TABLE2;
DELETE FROM TABLE1 WHERE VALUE IN
(SELECT VALUE FROM TABLE2 GROUP BY VALUE HAVING MAX(I) = 0);
SELECT * FROM TABLE1;
SELECT * FROM TABLE2;
The output of this script is shown below. First, the setting up of all the tables:
DROP TABLE TABLE1; DROP TABLE TABLE2;
TABLE1 DROPPED
TABLE2 DROPPED
CREATE TABLE TABLE1 (VALUE INTEGER);
TABLE1 CREATED
CREATE TABLE TABLE2 (VALUE INTEGER, I INTEGER);
TABLE2 CREATED
INSERT INTO TABLE1 VALUES ((5), (3));
INSERTED 2 ROWS
INSERT INTO TABLE2 VALUES ((5, 0), (5, 3), (3,0), 3, 0));
INSERTED 4 ROWS
And display them to ensure they're as expected:
SELECT * FROM TABLE1; SELECT * FROM TABLE2;
VALUE
-----
5
3
VALUE I
----- -
5 0
5 3
3 0
3 0
Then run the command to get rid of the relevant rows:
DELETE FROM TABLE1 WHERE VALUE IN
(SELECT VALUE FROM TABLE2 GROUP BY VALUE HAVING MAX(I) = 0);
DELETED 1 ROW
And you can see that the 3` row has disappeared from table 1 as desired:
SELECT * FROM TABLE1; SELECT * FROM TABLE2;
VALUE
-----
5
VALUE I
----- -
5 0
5 3
3 0
3 0