Insert into a table based on flag values of other table - sql

I have two tables
src (party_key,is_NRA,is_DOM,is_PEP)
and
dest(party_key,aml_type,aml_name)
What I want to do is -
If src.is_NRA = 1, then insert into dest values (src.party_key,'NRA','Is NRA')
If src.is_DOM = 1, then insert into dest values (src.party_key,'DOM','Is DOM')
.
.
One row in src table can have all 3 flags as '1'. In that case, I want to insert 3 separate rows in dest table.
How can I implement this in SQL?

Here you go
INSERT INTO dest(party_key,aml_type,aml_name)
SELECT src.party_key, 'NRA', 'Is NRA' FROM src WHERE src.is_NRA = 1;
INSERT INTO dest(party_key,aml_type,aml_name)
SELECT src.party_key, 'DOM', 'Is DOM' FROM src WHERE src.is_DOM = 1;
INSERT INTO dest(party_key,aml_type,aml_name)
SELECT src.party_key, 'PEP', 'Is PEP' FROM src WHERE src.is_PEP = 1;

INSERTing with three separate SELECTs may be fine for your purposes, but that's three separate table scans. INSERTing with one table scan is possible if you UNPIVOT (reference: http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx):
INSERT INTO
dest (
party_key,
aml_type,
aml_name
)
SELECT
party_key,
RIGHT([type], 3),
'Is ' + RIGHT([type], 3)
FROM
src
UNPIVOT (
flag FOR [type] IN (
is_NRA,
is_DOM,
is_PEP
)
) unpvt
WHERE
flag = 1

Am I missing something?
IF src.is_dom = 1 AND src.is_NRA = 1 AND src.is_PEP = 1,
THEN
INSERT INTO dest (party_key, aml_type, aml_name)
VALUES (src.party_key, 'DOM', 'Is DOM'), (src.party_key,'NRA','Is NRA'), (src.party_key,'PEP','Is PEP')

Related

Does WHEN clause in an insert all query when loading into multiple tables in Snowflake add a virtual field over each row and then load in bulk?

How WHEN clause evaluate values of columns in order to insert only new values and skip existing ones when using the following query:
INSERT ALL
WHEN (SELECT COUNT(*) FROM DEST WHERE DEST.ID = NEW_ID) = 0 THEN
INSERT INTO DEST (ID) VALUES (NEW_ID)
SELECT NEW_ID FROM SRC
I tried with WHEN NEW_ID NOT IN (SELECT...) THEN
But it didn't work and threw an error of unsupported.
Does it create a virtual column in all rows with values of true or false and then add all rows having true as a result?
Using EXISTS:
INSERT ALL
WHEN NOT EXISTS (SELECT 1 FROM DEST WHERE DEST.ID = NEW_ID) THEN
INTO DEST (ID) VALUES (NEW_ID)
SELECT NEW_ID FROM SRC;
Sample data:
CREATE TABLE DEST(ID INT);
INSERT INTO DEST VALUES(1);
CREATE TABLE SRC(NEW_ID INT);
INSERT INTO SRC VALUES (1),(2);
SELECT * FROM DEST;
-- 1
--EXPLAIN USING TABULAR
INSERT ALL
WHEN NOT EXISTS (SELECT 1 FROM DEST WHERE DEST.ID = NEW_ID) THEN
INTO DEST (ID) VALUES (NEW_ID)
SELECT NEW_ID FROM SRC;
SELECT * FROM DEST;
-- 1
-- 2

Updating thousands of records with different values

I've been given a spreadsheet in the format of :
Id | Val
1 57
2 99
There's approximately 10,000 records - Any ideas to handle the query below for 10,000 records without manually writing each case statement, tediously. Thanks.
update person
SET val = (
case
when Id = 1 then 57
when Id = 2 then 99
end),
where Id in (1, 2)
Quick and dirty? here you go
Add a new spredsheet call the old one datatable
In the first row first column you write
"Update person set val = ("
in the second column you link to the value on datatable spreadsheet
third column ") where ID = ("
fourth column you link to the ID of the datatable spreadsheet
fifth column ")"
Then you mark the whole row and pull it downwards to row 10000
Copy past into query escecute
I think this example can be help you :
CREATE TABLE #Person
(PrimaryKey int PRIMARY KEY,
ValueSome varchar(50)
);
GO
CREATE TABLE #MySpreadSheet
(PrimaryKey int PRIMARY KEY,
ValueSpread varchar(50)
);
GO
INSERT INTO #Person
SELECT 1, 'someValue'
INSERT INTO #Person
SELECT 2, 'someValueBeforeUpdate'
INSERT INTO #Person
SELECT 3, ''
INSERT INTO #MySpreadSheet
SELECT 1, '45'
INSERT INTO #MySpreadSheet
SELECT 2, '56'
INSERT INTO #MySpreadSheet
SELECT 3, '34'
SELECT * FROM #Person
SELECT * FROM #MySpreadSheet
UPDATE P SET P.ValueSome = SS.ValueSpread FROM #Person P JOIN #MySpreadSheet SS ON P.PrimaryKey = SS.PrimaryKey
SELECT * FROM #Person
DROP TABLE #Person
DROP TABLE #MySpreadSheet
If anyones interested, I went with this :
CREATE TABLE #TempTable(
Id int,
val int
)
INSERT INTO #TempTable (Id, val)
Values (1, 57),
(2, 99)
Update Person
Set Id = tp.Id,
val = tp.val
FROM Person p
INNER JOIN #TempTable as tp on tp.Id = p.Id
create table #example (id int , value int)
insert into #example (id, value) values (1, 10)
insert into #example (id, value) values (2, 20)
select * from #example
id value
1 10
2 20
update #example
set value = case when id = 1 then 100
when id = 2 then 200 end
where id in (1,2)
select * from #example
id value
1 100
2 200

Add empty rows to results

I want to add empty rows to results fetched from a select statement. For example, if the select query fetch 4 rows then 2 empty rows needs to be fetched. Objective should be the number of rows fetched should be 6 every time. The number of rows fetched will be 6 maximum if there are 6 rows with data.
Any idea?
In SQL-SERVER You can create temp table to update It with empty rows and you can use WHILE to insert desired number of rows with empty values. Something like:
-- Create temp table to update data with empty rows
CREATE TABLE #HoldEmptyRows
(
Id NVARCHAR(20),
CustomerName NVARCHAR(20),
CustomerEmail NVARCHAR(20)
)
-- Insert data from SourceTable to temp
INSERT INTO #HoldEmptyRows
SELECT * FROM SourceTable
-- Do while count from temp table < of desired number insert empty rows
WHILE ((SELECT COUNT(*) cnt FROM #HoldEmptyRows) < 6)
BEGIN
INSERT INTO #HoldEmptyRows VALUES ('', '', '')
END
SELECT * FROM #HoldEmptyRows
DEMO AT SQL FIDDLE
Try the below logic:
with cte as
(
select 0 as col1
union all
select col1+1 from cte where cte.col1<10
)
select * into #temp1 from cte
create table #test
(rownum int,col1 varchar(100))
declare #i int=1
while (#i<=6)
begin
insert into #test
select * from
(select row_Number() over (order by (Select 0))rownum, * from #temp1)x
where rownum=#i
Set #i=#i+1
end
select case when rownum>4 then '' else col1 end as col1 from #test

How to use multiple values in case statement in SQL server

Consider the below
Declare #t table(Val int, name varchar(100))
Insert into #t select 1,'name1'
union all select 1,'name2'
union all select 2,'name3'
union all select 3,'name4'
If I want to get the records pertainig to Val 1 or 2 the choice is an IN clause. But we have some condition based on which the values needs to be choosen. Henceforth, we are going ahead with CASE approach as under
declare #type int = 1
select *
from #t
where val = case when #type =1 then 1 end or
val = case when #type =1 then 2
end
It works fine as select * from #t where val in (1,2)(we cannot use this as the value has to be determined at runtime and we are not using any dynamic query). Is there any other way to simulating the IN clause?
This is just for the sake of knowledge.
Thanks
Assuming that your code takes a single values as a parameter, but that the value relates to a list of values, you could just use a mapping table...
CREATE PROCEDURE pseudo_in_clause (#type INT)
AS
DECLARE #map TABLE (
type INT,
val INT,
PRIMARY KEY (type, val)
)
INSERT INTO #map (type, val) VALUES (1, 1),
(1, 2),
(2, 3)
SELECT
*
FROM
yourTable AS data
INNER JOIN
#map AS map
ON data.val = map.val
WHERE
map.type = #type
The map could be a permanent table, a temp table such as above, function, etc.
Alternatively, you can still use an IN clause in the CASE statement...
SELECT
*
FROM
yourTable AS data
WHERE
CASE WHEN #type = 1 AND data.val IN (1,2) THEN 1
WHEN #type = 2 AND data.val IN (3,4) THEN 1
ELSE 0
END = 1
Personally I prefer the JOIN version.
Do you have to use CASE? This should work as well:
…
WHERE #type = 1 AND data.val IN (1, 2)
OR #type = … AND data.val IN (…)
OR …
Although I must say that I like #Dems's suggestion about using a join best of all. Note that you could use an inline table instead of a table variable, thus making the entire thing a single query:
SELECT *
FROM yourTable AS data
INNER JOIN (
VALUES
(1, 1),
(1, 2),
(2, 3)
) AS map ON data.val = map.val
WHERE map.type = #type

Delete duplicated rows and Update references

How do I Delete duplicated rows in one Table and update References in another table to the remaining row? The duplication only occurs in the name. The Id Columns are Identity columns.
Example:
Assume we have two tables Doubles and Data.
Doubles table (
Id int,
Name varchar(50)
)
Data Table (
Id int,
DoublesId int
)
Now I Have Two entries in the Doubls table:
Id Name
1 Foo
2 Foo
And two entries in the Data Table:
ID DoublesId
1 1
2 2
At the end there should be only one entry in the Doubles Table:
Id Name
1 Foo
And two entries in the Data Table:
Id DoublesId
1 1
2 1
In the doubles Table there can be any number of duplicated rows per name (up to 30) and also regular 'single' rows.
I've not run this, but hopefully it should be correct, and close enough to the final soln to get you there. Let me know any mistakes if you like and I'll update the answer.
--updates the data table to the min ids for each name
update Data
set id = final_id
from
Data
join
Doubles
on Doubles.id = Data.id
join
(
select
name
min(id) as final_id
from Doubles
group by name
) min_ids
on min_ids.name = Doubles.name
--deletes redundant ids from the Doubles table
delete
from Doubles
where id not in
(
select
min(id) as final_id
from Doubles
group by name
)
Note: I have taken the liberty to rename your Id's to DoubleID and DataID respectively. I find that eassier to work with.
DECLARE #Doubles TABLE (DoubleID INT, Name VARCHAR(50))
DECLARE #Data TABLE (DataID INT, DoubleID INT)
INSERT INTO #Doubles VALUES (1, 'Foo')
INSERT INTO #Doubles VALUES (2, 'Foo')
INSERT INTO #Doubles VALUES (3, 'Bar')
INSERT INTO #Doubles VALUES (4, 'Bar')
INSERT INTO #Data VALUES (1, 1)
INSERT INTO #Data VALUES (1, 2)
INSERT INTO #Data VALUES (1, 3)
INSERT INTO #Data VALUES (1, 4)
SELECT * FROM #Doubles
SELECT * FROM #Data
UPDATE #Data
SET DoubleID = MinDoubleID
FROM #Data dt
INNER JOIN #Doubles db ON db.DoubleID = dt.DoubleID
INNER JOIN (
SELECT db.Name, MinDoubleID = MIN(db.DoubleID)
FROM #Doubles db
GROUP BY db.Name
) dbmin ON dbmin.Name = db.Name
/* Kudos to quassnoi */
;WITH q AS (
SELECT Name, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Name) AS rn
FROM #Doubles
)
DELETE
FROM q
WHERE rn > 1
SELECT * FROM #Doubles
SELECT * FROM #Data
Take a look at this one, i have tried this, working fine
--create table Doubles ( Id int, Name varchar(50))
--create table Data( Id int, DoublesId int)
--select * from doubles
--select * from data
Declare #NonDuplicateID int
Declare #NonDuplicateName varchar(max)
DECLARE #sqlQuery nvarchar(max)
DECLARE DeleteDuplicate CURSOR FOR
SELECT Max(id),name AS SingleID FROM Doubles
GROUP BY [NAME]
OPEN DeleteDuplicate
FETCH NEXT FROM DeleteDuplicate INTO #NonDuplicateID, #NonDuplicateName
--Fetch next record
WHILE ##FETCH_STATUS = 0
BEGIN
--select b.ID , b.DoublesID, a.[name],a.id asdasd
--from doubles a inner join data b
--on
--a.ID=b.DoublesID
--where b.DoublesID<>#NonDuplicateID
--and a.[name]=#NonDuplicateName
print '---------------------------------------------';
select
#sqlQuery =
'update b
set b.DoublesID=' + cast(#NonDuplicateID as varchar(50)) + '
from
doubles a
inner join
data b
on
a.ID=b.DoublesID
where b.DoublesID<>' + cast(#NonDuplicateID as varchar(50)) +
' and a.[name]=''' + cast(#NonDuplicateName as varchar(max)) +'''';
print #sqlQuery
exec sp_executeSQL #sqlQuery
print '---------------------------------------------';
-- now move the cursor
FETCH NEXT FROM DeleteDuplicate INTO #NonDuplicateID ,#NonDuplicateName
END
CLOSE DeleteDuplicate --Close cursor
DEALLOCATE DeleteDuplicate --Deallocate cursor
---- Delete duplicate rows from original table
DELETE
FROM doubles
WHERE ID NOT IN
(
SELECT MAX(ID)
FROM doubles
GROUP BY [NAME]
)
Please try and let me know if this helped you
Thanks
~ Aamod
If you are using MYSQL following worked for me. I did it for 2 steps
Step 1 -> Update all Data rows to one Double table reference (with lowest id)
Step 2 -> Delete all duplicates with keeping lowest id
Step 1 ->
update Data
join
Doubles
on Data.DoublesId = Doubles.id
join
(
select name, min(id) as final_id
from Doubles
group by name
) min_ids
on min_ids.name = Doubles.name
set DoublesId = min_ids.final_id;
Step 2 ->
DELETE c1 FROM Doubles c1
INNER JOIN Doubles c2
WHERE
c1.id > c2.id AND
c1.name = c2.name;