Sql insert multiple rows if not exists - sql

I have a sql table that has two columns id and name. I have list of names about 20 and I need to write a query that checks if name exists before insert.
Is there a better way of doing this rather then just having the below query 20 times but with different names (I need do this in t-sql):
IF NOT EXISTS(SELECT*
FROM mytable
WHERE name = 'Dan')
BEGIN
INSERT INTO mytable
(name)
VALUES ('dan')
END

INSERT INTO MyTable (Name)
SELECT NewNames.Name
FROM ( VALUES ('Name1'), ('Name2'), ('Name3') ) AS NewNames (Name)
WHERE NOT EXISTS ( SELECT 1
FROM MyTable AS MT
WHERE MT.Name = NewNames.Name );

I think you could use a merge statement:
MERGE INTO myTable AS Target
USING (VALUES ('name1'),('name2'),('...')) AS source (NAME)
ON Target.NAME = Source.NAME
WHEN NOT MATCHED BY TARGET THEN
INSERT (NAME) VALUES (name)

You can filter values with NOT EXISTS
INSERT INTO myTable (
Name
)
SELECT DISTINCT
Name
FROM (
VALUES ('Name 1'),
('Name 2')
) AS NewNames(Name)
WHERE
NOT EXISTS (SELECT 1 FROM TargetTable WHERE myTable.Name = NewNames.Name)
If your new names are in another table, you can change the select query in the above one.
Please note, that the DISTINCT keyword is necessary to filter out the duplications in the source data.

I would do this using insert:
with names as (
select 'Dan' as name union all
select 'name2' union all
. . .
)
insert into myTable(name)
select distinct name
from myTable
where not exists (select 1 from mytable t2 where t2.name = t.name);
Note: you may want to create a unique index on mytable(name) so the database does the checking for duplicates.

untested so there might be some minor errors:
merge into mytable x
using (
values ('name1')
, ('name2')
, ...
, ('namen')
) as y (name)
on x.name = y.name
when not matched then
insert (name)
values (y.name)

INSERT INTO MyTable (Name)
SELECT Name FROM
(
VALUES ('Name 1'),
('Name 2')
) AS Names(Name)
WHERE Name NOT IN
(
SELECT Name FROM MyTable
)

INSERT IGNORE INTO myTable (column1, column2) VALUES (val1, val2),(val3,val4),(val5,val6);
INSERT IGNORE will allow skip on duplicate values

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;

How to insert conditionally in Oracle?

I've read here that the syntax looks like this:
INSERT
WHEN ([Condition]) THEN
INTO [TableName] ([ColumnName])
VALUES ([VALUES])
ELSE
INTO [TableName] ([ColumnName])
VALUES ([VALUES])
SELECT [ColumnName] FROM [TableName];
But I don't want to provide values from another table. I just want to type them, so I've got:
INSERT
WHEN EXISTS (SELECT 1 FROM FOO WHERE NAME = 'JOE')
THEN
INTO BAR (NAME, AGE)
VALUES ('JOE', 50)
and this produces exception: ORA-00928: missing SELECT keyword.
I want to perform an insert if given value is found in another table.
Using with select works. Your query wasn't working because there is a problem with values keyword when inserting conditionally.
INSERT
WHEN EXISTS (SELECT 1 FROM FOO WHERE NAME = 'JOE')
THEN
INTO BAR (NAME, AGE)
SELECT 'JOE', 50 FROM DUAL
So, I've found an indirect way here and solution for my question would be:
INSERT INTO BAR (NAME, AGE)
SELECT 'JOE', 50
FROM DUAL
WHERE EXISTS (SELECT 1 FROM FOO WHERE NAME = 'JOE')
but it doesn't explain why I have to use SELECT statement in INSERT WHEN

Can I use "if not exists" to insert a row if the row is not already present in sql server?

insert into Attributes (Id, Disabled, AttributeValue)
values (#id, #disabled, #attr_value)
if not exists
(
select * from Attributes
where
Id = #id
)
Not sure, if this is a valid query.
I have seen people use where not exists. What is the difference and how to use where not exists? When I put where not exists, it is saying "Incorrect syntax near where."
I checked these question as well. But, it doesn't seem to have query to insert using if not exists.
Only inserting a row if it's not already there and
sql conditional insert if row doesn't already exist
Am I missing something? Should I only use where not exists?
Change it to INSERT INTO SELECT
INSERT INTO Attributes (Id, Disabled, AttributeValue)
SELECT #id, #disabled, #attr_value
WHERE NOT EXISTS
(
select * from Attributes
where
Id = #id
)
You would need to execute something like this
IF NOT EXISTS (select 1 from Attributes where Id = #id)
BEGIN
insert into Attributes (Id, Disabled, AttributeValue)
values (#id, #disabled, #attr_value)
END
This is typically done with an else clause to update the row if it exists.
Consider using MERGE:
MERGE INTO Attributes
USING ( values (#id, #disabled, #attr_value ) )
AS source ( Id, Disabled, AttributeValue )
ON source.Id = Attributes.Id
WHEN NOT MATCHED THEN
INSERT ( Id, Disabled, AttributeValue )
VALUES ( Id, Disabled, AttributeValue );
One advantage is that you can also update the values when the Id does exist e.g.
MERGE INTO Attributes
USING ( values (#id, #disabled, #attr_value ) )
AS source ( Id, Disabled, AttributeValue )
ON source.Id = Attributes.Id
WHEN MATCHED THEN
UPDATE
SET Id = source.Id,
Disabled = source.Disabled,
AttributeValue = source.AttributeValue
WHEN NOT MATCHED THEN
INSERT ( Id, Disabled, AttributeValue )
VALUES ( Id, Disabled, AttributeValue );

sql like clause multiple values

I have a table with multiple words, from 1 to n.
declare #words table
(
word varchar(100) not null
)
insert into #words (word) values ('word1')
insert into #words (word) values ('word2')
insert into #words (word) values ('word3')
declare #tablea table
(
column1 varchar(100) not null
)
insert into #tablea (column1) values ('aword1a aword2a aword3a')
insert into #tablea (column1) values ('word2a')
insert into #tablea (column1) values ('word3a')
Im having trouble to write a query to select from a table where a column is like these words, and I need the AND operator. If the table contains word1, word2, word3, the like clause must match the three words, it means, I want to return the first row in tablea.
select *
from tablea
where
column1 like ?
Updated:
select t.column1
from #tablea t
inner join #words w on charindex(w.word, t.column1) > 0
group by t.column1
having count(distinct w.word) = (select count(*) from #words)
Since any one column needs to contain all the values in the #words table, I would use a not exists, and try to find a value in #words that isn't contained in the column1 field.
select
*
from
#tablea a
where not exists (
select 1
from #words w
where a.column1 not like '%' + w.word + '%'
)
This will do it, but I'm not sure how extensible it is:
SELECT column1
FROM #tablea t
JOIN #words w ON t.column1 LIKE '%'+w.word+'%'
GROUP BY column1
HAVING COUNT(*) = (SELECT COUNT(*) FROM #words)
In the long run, you may be better off implementing Full Text Search.

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).