union all with not exists and insert into - sql

I am trying to write a query in which i should verify if the records are already there, if they are, don't insert the data again.
I am writing this as an example, I don't know the correct syntax for what i'm trying to achieve. Please find my try below.
select * from
(
insert into dbo.myTable
select mt.* from #myTemp mt
union all
select * from #someTemp1
union all
select * from #someTemp2
) tb
where not exists ( select tb.* )
Is this the right way to use insert into with union all if not exists?
I found some examples with select union all where not exists but I would like to see one with insert as well.
I am also curios if it's possible to do this without using merge .

You can use MERGE as suggested in comments or just substract from sum existing values.
CREATE TABLE #myTable(col INT);
CREATE TABLE #myTemp(col INT);
CREATE TABLE #someTemp1(col INT);
CREATE TABLE #someTemp2(col INT);
INSERT INTO #myTable(col) VALUES (1), (2), (3);
INSERT INTO #myTemp(col) VALUES (10), (20), (30);
INSERT INTO #someTemp1(col) VALUES (1), (2), (3);
INSERT INTO #someTemp2(col) VALUES (11), (2), (31);
INSERT INTO #myTable(col)
(
SELECT mt.col FROM #myTemp mt
UNION ALL
SELECT col FROM #someTemp1
UNION ALL
SELECT col FROM #someTemp2
)
EXCEPT
SELECT col FROM #myTable;
SELECT *
FROM #myTable;
LiveDemo

Related

Insert multiple rows in a single query using results of a select statement

I am looking for a compact way to do this - insert multiple rows into a table with values from multiple columns of a row from another table. My destination table is really a list with a single column:
declare #stringList table
(
val nvarchar(100)
)
This is how we can insert multiple rows:
INSERT INTO #stringList ( val ) VALUES
Val1, Val2, Val3, ...
This is how we insert from a select:
INSERT INTO #stringList
SELECT col1 FROM table1 where id=something
But I cannot seem to find a way to use both at the same time.
I can select from one column:
insert into #stringList (val)
select col1 from table1 where id=something
But it doesn't extend to multiple columns:
insert into #stringList (val)
select col1, col2 from table1 where id=something
--The select list for the INSERT statement contains more items than the insert list. The number of SELECT values must match the number of INSERT columns.
I have tried various ways including using parentheses, but the syntax is not accepted:
insert into #stringList (val)
(select col1 from table1 where id=something,
select col2 from table1 where id=something
Any idea if what I want is doable?
You can unpivot using cross apply:
insert into #stringList (val)
select v.col
from table1 t1 cross apply
(values (t1.col1), (t1.col2)) v(col)
where t1.id = something;

Select different values into a table

Now I know how to select the outputs of a column into a table
select column1, column2 into #temptable
now, what if I just want to input the values myself into the table?
I know that
select 'a' [column1] into #temptable
works
and
select 'a' [column1] into #temptable
union
select 'b' [column1]
also works
but surely there's a less braindead way to get multiples lines of text into a row in SQL.
Demo on db<>fiddle
You might need Desired table
select v.value
into #temptable
from (
values ('a'), ('b'), ('c')
)v(value);
or
select 'a' as Value
into #temptable2
insert into #temptable2
values ('b'), ('c')
Do you just want values()?
select v.*
into #temptable
from (values ('a'), ('b')) v(column1);

Insert a table variable into a temp table with multiple columns (ID, Number, etc.)

I need to insert multiple Table variables into one temp table.
One of the table variables is:
DECLARE ##TempTable_Number TABLE (Number bigint)
insert into ##TempTable_Number (Number) values ('000000000000');
insert into ##TempTable_Number (Number) values ('100000000000');
This works for inserting just one table variable
select * into ##GlobalTempTable_1 from ##TempTable_Number
I have a couple more table variables like
DECLARE ##TempTable_ID TABLE (Number int)
insert into ##TempTable_ID (ID) values ('1');
insert into ##TempTable_ID (ID) values ('12');
etc...
I tried this to insert data from multiple table variables into one TempTable:
Select * into ####GlobalTempTable_1 From ##TempTable_ID, ##TempTable_Number;
The query goes to a continuous loop...
EDIT:
One of the table variables is:
DECLARE ##TempTable_Number TABLE (Number bigint, ID int)
insert into ##gvTempTable (Number) values ('21212321332332');
insert into ##gvTempTable (Number) values ('100000000000');
insert into ##gvTempTable (ID) values ('1');
insert into ##gvTempTable (ID) values ('12');
select * into ##GlobalTempTable from ##gvTempTable;
select * from ##GlobalTempTable;
This returns a kind of a cartesian product
Use UNION ALL:
SELECT ID
INTO ##GlobalTempTable_1
FROM ##TempTable_ID
UNION ALL
SELECT Number
FROM ##TempTable_Number;
LiveDemo
Select * into ####GlobalTempTable_1 From ##TempTable_ID, ##TempTable_Number;
The query goes to a continuous loop...
It is probably not loop but very long query. Keep in mind that you do Cartesian product.
So your query is the same as:
SELECT *
INTO ##GlobalTempTable_1
FROM ##TempTable_ID
CROSS JOIN ##TempTable_Number;
And the result is NxM records where N is number of records in first table and M in the second.
Try like this,
DECLARE #TempTable TABLE (
ID INT
,Number BIGINT
)
INSERT INTO #TempTable (Number)
VALUES ('21212321332332');
INSERT INTO #TempTable (Number)
VALUES ('100000000000');
INSERT INTO #TempTable (ID)
VALUES ('1');
INSERT INTO #TempTable (ID)
VALUES ('12');
--select * into #GlobalTempTable from ##gvTempTable;
--select * from ##GlobalTempTable;
SELECT *
FROM #TempTable
SELECT A.ID
,B.Number
FROM (
SELECT ID
,ROW_NUMBER() OVER (
ORDER BY ID
) TempId
FROM #TempTable
WHERE id IS NOT NULL
) A
INNER JOIN (
SELECT number
,ROW_NUMBER() OVER (
ORDER BY id
) TempId
FROM #TempTable
WHERE number IS NOT NULL
) B ON A.TempId = B.TempId

INSERT INTO with SELECT using OUTPUT

I want to store the pt_id into my temporary table by using OUTPUT, however I'm not inserting pt_id into ct_tarf, what should I do?
I get the following error:
The multi-part identifier 'pt_id' could not be bound.
Query:
DECLARE #tbl_ids_tarf TABLE (pt_id INT, pt_id_tarf INT)
INSERT INTO dbo.ct_tarf(tr_id_serv, tr_name, tr_money)
OUTPUT pt_id, inserted.tr_id INTO #tbl_ids_tarf(ptr_id, ptr_id_tarf)
SELECT
pt_id_serv, pt_name, pt_money
FROM
dbo.opr_prop_tar
WHERE
pt_id_tarf
SQL2008+:
Assuming that you want to insert into #tbl_ids_tarf (which is target of OUTPUT ... INTO clause) values from columns that are not returned by inserted or deleted virtual tables then one solution is to use MERGE statement instead of INSERT:
DECLARE #Target TABLE (
Col1 INT
)
INSERT #Target VALUES (1), (2);
DECLARE #Output TABLE (Col1 INT, ColB INT);
;WITH Source
AS (
SELECT *
FROM (VALUES (10, 100), (20, 200), (30, 300)) x(ColA, ColB)
)
MERGE INTO #Target x
USING Source y ON x.Col1 = y.ColA
WHEN NOT MATCHED BY TARGET THEN
INSERT (Col1) VALUES (y.ColA)
OUTPUT inserted.Col1, y.ColB INTO #Output (Col1, ColB);
-- ^-- y.ColB isn't returned by inserted or deleted virtual tables.
-- inserted and deleted are based on `#Target` table [variable]
SELECT * FROM #Output;
/*
Col1 ColB
----------- -----------
10 100
20 200
30 300
*/
You have several issues with your query - column naming is one, an incomplete WHERE clause is another, and a missing Inserted. prefix is the third.
Try this:
DECLARE #tbl_ids_tarf TABLE (pt_id INT, pt_id_tarf INT)
INSERT INTO dbo.ct_tarf(tr_id_serv, tr_name, tr_money)
OUTPUT inserted.pt_id, inserted.tr_id INTO #tbl_ids_tarf(pt_id, pt_id_tarf)
-- ********* ******************
SELECT
pt_id_serv, pt_name, pt_money
FROM
dbo.opr_prop_tar
WHERE
pt_id_tarf --........

Select records with order of IN clause

I have
SELECT * FROM Table1 WHERE Col1 IN(4,2,6)
I want to select and return the records with the specified order which i indicate in the IN clause
(first display record with Col1=4, Col1=2, ...)
I can use
SELECT * FROM Table1 WHERE Col1 = 4
UNION ALL
SELECT * FROM Table1 WHERE Col1 = 6 , .....
but I don't want to use that, cause I want to use it as a stored procedure and not auto generated.
I know it's a bit late but the best way would be
SELECT *
FROM Table1
WHERE Col1 IN( 4, 2, 6 )
ORDER BY CHARINDEX(CAST(Col1 AS VARCHAR), '4,2,67')
Or
SELECT CHARINDEX(CAST(Col1 AS VARCHAR), '4,2,67')s_order,
*
FROM Table1
WHERE Col1 IN( 4, 2, 6 )
ORDER BY s_order
You have a couple of options. Simplest may be to put the IN parameters (they are parameters, right) in a separate table in the order you receive them, and ORDER BY that table.
The solution is along this line:
SELECT * FROM Table1
WHERE Col1 IN(4,2,6)
ORDER BY
CASE Col1
WHEN 4 THEN 1
WHEN 2 THEN 2
WHEN 6 THEN 3
END
select top 0 0 'in', 0 'order' into #i
insert into #i values(4,1)
insert into #i values(2,2)
insert into #i values(6,3)
select t.* from Table1 t inner join #i i on t.[in]=t.[col1] order by i.[order]
Replace the IN values with a table, including a column for sort order to used in the query (and be sure to expose the sort order to the calling application):
WITH OtherTable (Col1, sort_seq)
AS
(
SELECT Col1, sort_seq
FROM (
VALUES (4, 1),
(2, 2),
(6, 3)
) AS OtherTable (Col1, sort_seq)
)
SELECT T1.Col1, O1.sort_seq
FROM Table1 AS T1
INNER JOIN OtherTable AS O1
ON T1.Col1 = O1.Col1
ORDER
BY sort_seq;
In your stored proc, rather than a CTE, split the values into table (a scratch base table, temp table, function that returns a table, etc) with the sort column populated as appropriate.
I have found another solution. It's similar to the answer from onedaywhen, but it's a little shorter.
SELECT sort.n, Table1.Col1
FROM (VALUES (4), (2), (6)) AS sort(n)
JOIN Table1
ON Table1.Col1 = sort.n
I am thinking about this problem two different ways because I can't decide if this is a programming problem or a data architecture problem. Check out the code below incorporating "famous" TV animals. Let's say that we are tracking dolphins, horses, bears, dogs and orangutans. We want to return only the horses, bears, and dogs in our query and we want bears to sort ahead of horses to sort ahead of dogs. I have a personal preference to look at this as an architecture problem, but can wrap my head around looking at it as a programming problem. Let me know if you have questions.
CREATE TABLE #AnimalType (
AnimalTypeId INT NOT NULL PRIMARY KEY
, AnimalType VARCHAR(50) NOT NULL
, SortOrder INT NOT NULL)
INSERT INTO #AnimalType VALUES (1,'Dolphin',5)
INSERT INTO #AnimalType VALUES (2,'Horse',2)
INSERT INTO #AnimalType VALUES (3,'Bear',1)
INSERT INTO #AnimalType VALUES (4,'Dog',4)
INSERT INTO #AnimalType VALUES (5,'Orangutan',3)
CREATE TABLE #Actor (
ActorId INT NOT NULL PRIMARY KEY
, ActorName VARCHAR(50) NOT NULL
, AnimalTypeId INT NOT NULL)
INSERT INTO #Actor VALUES (1,'Benji',4)
INSERT INTO #Actor VALUES (2,'Lassie',4)
INSERT INTO #Actor VALUES (3,'Rin Tin Tin',4)
INSERT INTO #Actor VALUES (4,'Gentle Ben',3)
INSERT INTO #Actor VALUES (5,'Trigger',2)
INSERT INTO #Actor VALUES (6,'Flipper',1)
INSERT INTO #Actor VALUES (7,'CJ',5)
INSERT INTO #Actor VALUES (8,'Mr. Ed',2)
INSERT INTO #Actor VALUES (9,'Tiger',4)
/* If you believe this is a programming problem then this code works */
SELECT *
FROM #Actor a
WHERE a.AnimalTypeId IN (2,3,4)
ORDER BY case when a.AnimalTypeId = 3 then 1
when a.AnimalTypeId = 2 then 2
when a.AnimalTypeId = 4 then 3 end
/* If you believe that this is a data architecture problem then this code works */
SELECT *
FROM #Actor a
JOIN #AnimalType at ON a.AnimalTypeId = at.AnimalTypeId
WHERE a.AnimalTypeId IN (2,3,4)
ORDER BY at.SortOrder
DROP TABLE #Actor
DROP TABLE #AnimalType
ORDER BY CHARINDEX(','+convert(varchar,status)+',' ,
',rejected,active,submitted,approved,')
Just put a comma before and after a string in which you are finding the substring index or you can say that second parameter.
And first parameter of CHARINDEX is also surrounded by , (comma).