Continue insert if one row fails in SQL Server - sql-server-2012

I have a question about SQL Server - how to continue insert if one row fails?
I have two tables, emp and empref. I want insert rows into the empref table using emp table.
While inserting, one of the rows fails with an "unexpected format" error. emp and empref both have the same columns, but datatypes are different.
Source : emp
CREATE TABLE [dbo].[emp]
(
[id] [varchar](50) NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
INSERT INTO [dbo].[emp] ([id], [name], [sal]) VALUES (N'1', N'abc', 100)
INSERT INTO [dbo].[emp] ([id], [name], [sal]) VALUES (N'2', N'xyz', 200)
INSERT INTO [dbo].[emp] ([id], [name], [sal]) VALUES (N'a4', N'un', 300)
In the empref ref expected int value but one values alphanumeric values.
CREATE TABLE [dbo].[empref]
(
[id] [int] NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
Expected result in empref table :
id |name | name
---+-----+------
1 |abc | 100
2 |xyz | 200
I tried like this:
BEGIN TRY
INSERT INTO empref
SELECT * FROM emp
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE() erro
END CATCH
This query is not returning the expected result.
Please tell me how to write the query to achieve this task in SQL Server

You can use TRY_CAST to check if the conversion will work
INSERT INTO empref
(id, name, sal)
SELECT
TRY_CAST(e.id AS int),
e.name,
e.sal
FROM emp e
WHERE TRY_CAST(e.id AS int) IS NOT NULL;
db<>fiddle
Note: Always specify columns to be inserted into.

Related

SQL Server: Split Data in a column based on a delimiter and then join with reference table to get ID values associated

I would like to achieve the column Expected in the screenshot below. Could you please help me achieve this on Synapse Datawarehouse using the following table scripts and sample data.
Note:
This is just a sample data set. The original Users table would have millions of rows.
Users column can more than N number of users separated with delimiter ';'
CREATE TABLE [BTS_Test].[Users]
(
[Date] [date] NOT NULL,
[Users] [varchar](500) NOT NULL
)
WITH
(
DISTRIBUTION = ROUND_ROBIN
);
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Rupesh; Suresh; Yogesh');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Anne; Prudvi; Mahesh');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Bobby');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Crystal; Abella');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Balaji; Kishan; Silpa; Sindhu Srinivas; Kiran');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-12','Cindrella');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-12','Monika; Chandler');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-13','Niko Paul');
CREATE TABLE [BTS_Test].[Student]
(
[ID] [int] NOT NULL,
[StudentName] [varchar](500) NOT NULL
)
WITH
(
DISTRIBUTION = REPLICATE
);
INSERT INTO [BTS_Test].[Student] VALUES(1,'Rupesh');
INSERT INTO [BTS_Test].[Student] VALUES(2,'Suresh');
INSERT INTO [BTS_Test].[Student] VALUES(3,'Yogesh');
INSERT INTO [BTS_Test].[Student] VALUES(4,'Anne');
INSERT INTO [BTS_Test].[Student] VALUES(5,'Prudvi');
INSERT INTO [BTS_Test].[Student] VALUES(6,'Mahesh');
INSERT INTO [BTS_Test].[Student] VALUES(7,'Bobby');
INSERT INTO [BTS_Test].[Student] VALUES(8,'Crystal');
INSERT INTO [BTS_Test].[Student] VALUES(9,'Abella');
INSERT INTO [BTS_Test].[Student] VALUES(10,'Balaji');
INSERT INTO [BTS_Test].[Student] VALUES(11,'Kishan');
INSERT INTO [BTS_Test].[Student] VALUES(12,'Silpa');
INSERT INTO [BTS_Test].[Student] VALUES(13,'Sindhu Srinivas');
INSERT INTO [BTS_Test].[Student] VALUES(14,'Kiran');
INSERT INTO [BTS_Test].[Student] VALUES(15,'Cindrella');
INSERT INTO [BTS_Test].[Student] VALUES(16,'Monika');
INSERT INTO [BTS_Test].[Student] VALUES(17,'Chandler');
INSERT INTO [BTS_Test].[Student] VALUES(18,'Niko Paul');
Here is an option using JSON to keep the sequence. Performance over millions of rows??? Just keep in mind there are penalties for storing delimited data.
Example
Select *
From [Users] A
Cross Apply (
Select Expected = string_agg(ID,';') WITHIN GROUP ( ORDER BY [key] )
From OpenJSON( '["'+replace(string_escape([Users],'json'),';','","')+'"]' )
Join [Student] on trim(Value)=StudentName
) B
Results
Date Users Expected
2023-01-11 Rupesh; Suresh; Yogesh 1;2;3
2023-01-11 Anne; Prudvi; Mahesh 4;5;6
2023-01-11 Bobby 7
2023-01-11 Crystal; Abella 8;9
2023-01-11 Balaji; Kishan; Silpa; Sindhu Srinivas; Kiran 10;11;12;13;14
2023-01-12 Cindrella 15
2023-01-12 Monika; Chandler 16;17
2023-01-13 Niko Paul 18
This produces results using STRING_SPLIT and XML:
SELECT u.[DATE], u.USERS, (STUFF((SELECT ';' + Y
FROM (select CAST(s.id AS VARCHAR) AS y from STRING_SPLIT (u.USERS, ';') sp
INNER JOIN STUDENT s on s.STUDENTNAME = trim(sp.Value)) X
FOR XML PATH('')) ,1,1,'')) as EXPECTED
FROM USERS u

SQL Server: Insert batch with output clause

I'm trying the following
Insert number of records to table A with a table-valued parameter (tvp). This tvp has extra column(s) that are not in A
Get the inserted ids from A and the corresponding extra columns in the the tvp and add them to another table B
Here's what I tried
Type:
CREATE TYPE tvp AS TABLE
(
id int,
otherid int,
name nvarchar(50),
age int
);
Tables:
CREATE TABLE A (
[id_A] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50),
[age] [int]
);
CREATE TABLE B (
[id_B] [int] IDENTITY(1,1) NOT NULL,
[id_A] [int],
[otherid] [int]
);
Insert:
DECLARE #a1 AS tvp;
DECLARE #a2 AS tvp
-- create a tvp (dummy data here - will be passed to as a param to an SP)
INSERT INTO #a1 (name, age, otherid) VALUES ('yy', 10, 99999), ('bb', 20, 88888);
INSERT INTO A (name, age)
OUTPUT
inserted.id_A,
inserted.name,
inserted.age,
a.otherid -- <== isn't accepted here
INTO #a2 (id, name, age, otherid)
SELECT name, age FROM #a1 a;
INSERT INTO B (id_A, otherid) SELECT id, otherid FROM #a2
However, this fails with The multi-part identifier "a.otherid" could not be bound., which I guess is expected because columns from other tables are not accepted for INSERT statement (https://msdn.microsoft.com/en-au/library/ms177564.aspx).
from_table_name
Is a column prefix that specifies a table included in the FROM clause of a DELETE, UPDATE, or MERGE statement that is used to specify the rows to update or delete.
So is there any other way to achieve this?
You cannot select value from a source table by using INTO operator.
Use OUTPUT clause in the MERGE command for such cases.
DECLARE #a1 AS tvp;
DECLARE #a2 AS tvp
INSERT INTO #a1 (name, age, otherid) VALUES ('yy', 10, 99999), ('bb', 20, 88888);
MERGE A a
USING #a1 a1
ON a1.id =a.[id_A]
WHEN NOT MATCHED THEN
INSERT (name, age)
VALUES (a1.name, a1.age)
OUTPUT inserted.id_A,
a1.otherId,
inserted.name,
inserted.age
INTO #a2;
INSERT INTO B (id_A, otherid) SELECT id, otherid FROM #a2

SQL Query to order by with case

Hi here I'm trying to put order by based on case. Here is my trail and I'm getting syntax error at 'END'
Can someone tell me whats wrong in this?
CREATE TABLE [Emp](
[Id] [nvarchar](50) NULL,
[Name] [varchar](50) NULL
) ON [PRIMARY]
GO
insert into emp values ('01','one')
insert into emp values ('02','Two')
insert into emp values ('3','Three')
insert into emp values ('10','Ten')
insert into emp values ('01A','oneA')
insert into emp values ('*','Star')
go
declare #sortby varchar(100)
set #sortby = 'Id'
select * from emp
ORDER BY
CASE #sortby
WHEN 'Id' THEN
CASE
WHEN ISNUMERIC(Id)=1
THEN CAST(Id as int)
WHEN PATINDEX('%[^0-9]%',Id) > 1
THEN CAST(LEFT(Id,PATINDEX('%[^0-9]%',Id) - 1) as int)
ELSE 2147483648
END
CASE
WHEN ISNUMERIC(Id)=1
THEN NULL
WHEN PATINDEX('%[^0-9]%',Id) > 1
THEN SUBSTRING(Id,PATINDEX('%[^0-9]%',Id) ,50)
ELSE Id
END
END,
Name

Ambiguity in Select Query

This is my test table:
CREATE TABLE [General].[Test]
(
[Name] NVARCHAR(20) NOT NULL,
[SSN] CHAR(10) NOT NULL,
CONSTRAINT [UK_Test_SSN]
UNIQUE NONCLUSTERED ([SSN]) WITH (IGNORE_DUP_KEY = OFF),
)
And I inserted some values:
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'901223476', N'Lol1');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'2591830061', N'Lol2');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'4431776273', N'Lol3');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'987654321', N'Lol4');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'123456789', N'Lol5');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'0123456789', N'Lol6');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'0012345678', N'Lol7');
INSERT INTO [General].[Test] ([SSN], [Name]) VALUES (N'123', N'Lol8');
And the first SELECT query:
SELECT
CASE
WHEN [T].[SSN] LIKE REPLICATE('[0-9]',10) THEN [T].[SSN]
ELSE 1000000000 + ROW_NUMBER() OVER(ORDER BY [T].[Name]) END AS [SSN]
FROM [General].[Test] AS [T];
GO
And the second query:
SELECT [T].[SSN] FROM [General].[Test] AS [T];
The ambiguity that I can't understand is about rows 6 and 7 whose [SSN] values start with 0
So for example about 6th row the first query returns 123456789 and second query return 0123456789, can anyone explain why? And I really need to get the real value of 0123456789 in the first query, what can I do?
You have two different datatypes being returned from your first column in the first query - in the first case, the CHAR(10) of the [SSN] is returned, in the ELSE case a large INT number. That's why SQL Server needs to convert one of the two datatypes to the other.
What you need to do, if you want to get back the CHAR(10), is to CAST the second expression to that datatype:
SELECT
CASE
WHEN [T].[SSN] LIKE REPLICATE('[0-9]', 10) THEN [T].[SSN]
ELSE CAST(1000000000 + ROW_NUMBER() OVER(ORDER BY [T].[Name]) AS CHAR(10))
END
FROM [General].[Test] AS [T];
Then you get back your CHAR(10) values - and nothing gets converted to a INT (or BIGINT) and thus looses it's leading zeroes:
(No column name)
1000000001
2591830061
4431776273
1000000004
1000000005
0123456789
0012345678
1000000008

SQL Spatial JOIN By Nearest Neighbor

In the data below I am looking for a query so I can join the results of the 2 tables by nearest neighbor.
Some of the results in dbo.Interests Table will not be in the dbo.Details Table,
This Question finds the k nearest poins for a single point, I need this query to further reconcile data between the 2 tables
How can I extend this SQL query to find the k nearest neighbors?
IF OBJECT_ID('dbo.Interests', 'U') IS NOT NULL DROP TABLE dbo.Interests;
IF OBJECT_ID('dbo.Details', 'U') IS NOT NULL DROP TABLE dbo.Details;
CREATE TABLE [dbo].[Interests](
[ID] [int] IDENTITY(1,1) NOT NULL,
[NAME] [nvarchar](255) NULL,
[geo] [geography] NULL,
)
CREATE TABLE [dbo].[Details](
[ID] [int] IDENTITY(1,1) NOT NULL,
[NAME] [nvarchar](255) NULL,
[geo] [geography] NULL,
)
/*** Sample Data ***/
/* Interests */
INSERT INTO dbo.Interests (Name,geo) VALUES ('Balto the Sled Dog',geography::STGeomFromText('POINT(-73.97101284538104 40.769975451779729)', 4326));
INSERT INTO dbo.Interests (Name,geo) VALUES ('Albert Bertel Thorvaldsen',geography::STGeomFromText('POINT(-73.955996808113582 40.788611756916609)', 4326));
INSERT INTO dbo.Interests (Name,geo) VALUES ('Alice in Wonderland',geography::STGeomFromText('POINT(-73.966714294355356 40.7748020248959)', 4326));
INSERT INTO dbo.Interests (Name,geo) VALUES ('Hans Christian Andersen',geography::STGeomFromText('POINT(-73.96756141015176 40.774416211045626)', 4326));
/* Details */
INSERT INTO dbo.Details(Name,geo) VALUES ('Alexander Hamilton',geography::STGeomFromText('POINT(-73.9645616688172 40.7810234271951)', 4326));
INSERT INTO dbo.Details(Name,geo) VALUES ('Arthur Brisbane',geography::STGeomFromText('POINT(-73.953249720745731 40.791599412827864)', 4326));
INSERT INTO dbo.Details(Name,geo) VALUES ('Hans Christian Andersen',geography::STGeomFromText('POINT(-73.9675614098224 40.7744162102582)', 4326));
INSERT INTO dbo.Details(Name,geo) VALUES ('Balto',geography::STGeomFromText('POINT(-73.9710128455336 40.7699754516397)', 4326));
A brute force approach will be to compute the distance between all details X interests records:
SELECT *
FROM
(
SELECT *, rank=dense_rank() over (partition by IName, IGeo order by dist asc)
FROM
(
SELECT D.NAME as DName, D.geo as DGeo,
I.NAME as IName, I.geo as IGeo,
I.geo.STDistance(D.geo) AS dist
FROM dbo.Details D CROSS JOIN dbo.Interests I
) X
) Y
WHERE rank <= #k
NotE: #k is the target number of matches you are after