How to handle Multivalue attribute in sql server - sql

I have a table in Data warehouse.
Create table customer
(
id int,
name varchar(30),
address varchar(50)
);
let data in table
insert into Customer values(1, 'Smith', 'abc,def, lkj');
insert into Customer values(2, 'James', 'pqr,lmn');
i want to split the table address column and insert new row if we have many values. Like
1 Smith abc
1 Smith def
1 Smith lkj
2 James pqr
2 James lmn
i have data of 100000 recrds, please help me in this regards.

You can use string_split() and adjust the insert statement:
insert into Customer (id, name, address)
select v.id, v.name, s.value
from (values (1, 'Smith', 'abc,def,lkj')
) v(id, name, address) cross apply
string_split(v.address, ',') s;
You might also want to add a check constraint on address so it does not contain a comma.
You would load from a staging table to the final table by doing:
insert into Customer (id, name, address)
select t.id, t.name, s.value
from staging t cross apply
string_split(v.address, ',') s;

Related

Get unique row based on 2 columns with duplicate values

I have a table with 3 columns and 6 rows:
As you can see based on the highlighted red text, Ash and Joey have the same Last name and Street address i.e. column "Last" and column "Street" have a duplicate value. I would like to only get one of them.
Desired result would be to get rows without duplicate values on the "Last" and "Street" columns:
Where only one of Ash or Joey is retained (I just used Ash in this example, but Joey would be fine too - just need 1 or the other, not both).
Is this even possible? Any advise appreciated, thanks.
P.S. the “Street” column is actually on a different table so the picture of the graph represents 2 tables already joined.
Since you don't care which record of the duplicates survives you can give this a shot. It'll actually keep the first one alphabetically by First
DROP TABLE IF EXISTS #t;
CREATE TABLE #t (First VARCHAR(255), Last VARCHAR(255), Street VARCHAR(255));
INSERT #t SELECT 'Ash', 'Williams', '123 Main';
INSERT #t SELECT 'Ben', 'O''Shea', '456 Grand';
INSERT #t SELECT 'Claire', 'Port', '543 Jasper';
INSERT #t SELECT 'Denise', 'Stone', '543 Jasper';
INSERT #t SELECT 'Erica', 'Thomas', '789 Holt';
INSERT #t SELECT 'Joey', 'Williams', '123 Main';
WITH dupes AS (
SELECT First,
Last,
Street,
ROW_NUMBER() OVER (PARTITION BY Last, Street ORDER BY First) RowNum
FROM #t
)
SELECT First, Last, Street
FROM dupes
WHERE RowNum = 1;
On the assumption you want to retain the person with the first name alpabetically, you can use the ROW_NUMBER window function to generate a new row number for each duplicate and use that to filter out the dupes:
CREATE TABLE Peeps
(
FirstName NVARCHAR(20),
LastName NVARCHAR(20),
Street NVARCHAR(20)
)
INSERT INTO Peeps
VALUES
('Ash','Williams','123 Main'),
('Ben','O''Shea','456 grand'),
('Claire','Port','543 Jasper'),
('Denise','Stone','543 Jasper'),
('Erica','Thomas','789 Holt'),
('Joey','Williams','123 Main')
SELECT FirstName,
LastName,
Street
FROM (
SELECT FirstName,
LastName,
Street,
ROW_NUMBER () OVER (PARTITION BY LastName,Street ORDER BY FirstName) AS RowN
FROM Peeps
) a
WHERE RowN = 1
DROP TABLE Peeps

Copy Sql Server Graph database with data

I am having a simple SQL Graph Database.
Database:
CREATE TABLE Person (
ID INTEGER PRIMARY KEY,
name VARCHAR(100)
) AS NODE;
CREATE TABLE City (
ID INTEGER PRIMARY KEY,
name VARCHAR(100)
) AS NODE;
CREATE TABLE Travels AS EDGE;
INSERT INTO Person VALUES (3,'Cecil');
INSERT INTO Person VALUES (4,'Diane');
INSERT INTO Person VALUES (2,'Bob');
INSERT INTO Person VALUES (1,'Alice');
Insert into City VALUES (1, 'Almaty')
Insert into City VALUES (2, 'Bangkok')
Insert into City VALUES (3, 'Casablanca')
Insert into City VALUES (4, 'Dublin')
INSERT INTO Travels VALUES ((SELECT $node_id FROM Person WHERE ID = 1),
(SELECT $node_id FROM City WHERE ID = 1));
INSERT INTO Travels VALUES ((SELECT $node_id FROM Person WHERE ID = 2),
(SELECT $node_id FROM City WHERE ID = 2));
INSERT INTO Travels VALUES ((SELECT $node_id FROM Person WHERE ID = 3),
(SELECT $node_id FROM City WHERE ID = 3));
INSERT INTO Travels VALUES ((SELECT $node_id FROM Person WHERE ID = 4),
(SELECT $node_id FROM City WHERE ID = 4));
I would like to copy these tables to a different tables. My goal is to make it within C#, but simple TSQL solution would be good enough.
CREATE TABLE Person2 (
ID INTEGER PRIMARY KEY,
name VARCHAR(100)
) AS NODE;
CREATE TABLE City2 (
ID INTEGER PRIMARY KEY,
name VARCHAR(100)
) AS NODE;
CREATE TABLE Travels2 AS EDGE;
I can copy data from Node tables easily, if i would read only user data and not an internal column $node_id:
insert into Person2(ID, name) (select Id, name from Person)
insert into City2(ID, name) (select id, name from City)
but in table Travels, I am having just this information:
select $edge_id, $from_id, $to_id from Travels :
{"type":"edge","schema":"dbo","table":"Travels","id":0} {"type":"node","schema":"dbo","table":"Person","id":3} {"type":"node","schema":"dbo","table":"City","id":0}
and in order to copy this, i would need to create a join over tables Person, City, Travels to get original IDS and then join it with Person2 and City2 to get new values $from_id, $to_id for Travels2
Another option would be to use functions Graph_ID_FROM_NODE_ID and NODE_ID_FROM_PARTS:
insert into Person2($node_id, ID, name)
(select ''+NODE_ID_FROM_PARTS(OBJECT_ID('dbo.Person2'),Graph_ID_FROM_NODE_ID($node_id)), Id, name from Person )
insert into City2($node_id, ID, name)
(select ''+NODE_ID_FROM_PARTS(OBJECT_ID('dbo.City2'),Graph_ID_FROM_NODE_ID($node_id)), Id, name from City )
Insert into Travels2 ($edge_id, $from_id, $to_id)
(select ''+EDGE_ID_FROM_PARTS(OBJECT_ID('dbo.Travels2'), Graph_ID_FROM_EDGE_ID($edge_id)), ''+NODE_ID_FROM_PARTS(OBJECT_ID('dbo.Person2'),Graph_ID_FROM_NODE_ID($from_id)), ''+NODE_ID_FROM_PARTS(OBJECT_ID('dbo.City2'),Graph_ID_FROM_NODE_ID($to_id)) from Travels
)
Probably, i don't need to copy ids of edges, so last insert would be a bit easier, but i wonder, if there is not any easier way how to copy graph tables.

SQL view / query to join data between 2 tables via a json field

Example table structure:
create table issues
(id int, title varchar(50), affectedclients varchar(max))
create table clients
(id int, name varchar(50))
insert into issues (id, title, affectedclients) values (1, 'Error when clicking save', '["1","2"]');
insert into issues (id, title, affectedclients) values (2, '404 error on url', '[3]');
insert into clients (id, name) values (1, 'Tesco');
insert into clients (id, name) values (2, 'Costa');
insert into clients (id, name) values (3, 'Boots');
insert into clients (id, name) values (4, 'Nandos');
I want to run a query so that I can get the data in the following format:
Id Title AffectedClients
1 Error when clicking save Tesco, Costa
2 404 error on url Boots
How can I achieve this please in the most performant way possible?
If this will be very easy with a properly normalized database then please provide an example.
You need to use OPENJSON() with explicit schema definition to parse the JSON text in the affectedclients column. After that you need to aggregate the names (using FOR XML PATH for SQL Server 2016+ or STRING_AGG() for SQL SQL Server 2017+).
Data:
create table issues
(id int, title varchar(50), affectedclients varchar(max))
create table clients
(id int, name varchar(50))
insert into issues (id, title, affectedclients) values (1, 'Error when clicking save', '["1","2"]');
insert into issues (id, title, affectedclients) values (2, '404 error on url', '[3]');
insert into clients (id, name) values (1, 'Tesco');
insert into clients (id, name) values (2, 'Costa');
insert into clients (id, name) values (3, 'Boots');
insert into clients (id, name) values (4, 'Nandos');
Statement for SQL Server 2016+:
SELECT
i.id,
i.title,
[affectedclients] = STUFF(
(
SELECT CONCAT(', ', c.[name])
FROM OPENJSON(i.affectedclients) WITH (id int '$') j
LEFT JOIN clients c on c.id = j.id
FOR XML PATH('')
), 1, 2, '')
FROM issues i
Statement for SQL Server 2017+:
SELECT i.id, i.title, STRING_AGG(c.name, ', ') AS affectedclients
FROM issues i
CROSS APPLY OPENJSON(i.affectedclients) WITH (id int '$') j
LEFT JOIN clients c ON c.id = j.id
GROUP BY i.id, i.title
ORDER BY i.id, i.title
Results:
-----------------------------------------------
id title affectedclients
-----------------------------------------------
1 Error when clicking save Tesco, Costa
2 404 error on url Boots

I need sql query for order by values of given parameters?

I need a query for order by given parameters
My table like this
ID Name Type
1 Argentine Standard
2 Spain Critical
3 France Critical
4 Germany Standard
5 Brazil Standard
6 Italy Standard
I am sending the parameter as Germany,Spain,Brazil,Argentine my output should be
ID Name Type
4 Germany Standard
2 Spain Critical
5 Brazil Standard
1 Argentine Standard
At present i used in query and i got the output in order by id that means it shows the result as in database order but i need to order by query parameter order?
can anyone help me for query?
according to your output I can suggest you this query. You can also alter order by clause as per your requirement:
select id,name,type from stack where name in('Germany','Spain','Brazil','Argentine') order by type,name,id desc
may be you are sending Comma Separated Input then we can convert them into rows and join with the table Data to get Required Output.
declare #t varchar(50) = ' Germany,Spain,Brazil,Argentine'
Declare #tt table (ID INT IDENTITY(1,1),val varchar(10))
insert into #tt (val)
SELECT
LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Certs
FROM
(
SELECT CAST('<XMLRoot><RowData>' + REPLACE(#t,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
)t
CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
DECLARE #Table1 TABLE
(ID int, Name varchar(9), Type varchar(8))
;
INSERT INTO #Table1
(ID, Name, Type)
VALUES
(1, 'Argentine', 'Standard'),
(2, 'Spain', 'Critical'),
(3, 'France', 'Critical'),
(4, 'Germany', 'Standard'),
(5, 'Brazil', 'Standard'),
(6, 'Italy', 'Standard')
;
select T.ID,TT.val,T.Type from #Table1 T
INNER JOIN #tt TT
ON T.Name = TT.val
ORDER BY TT.ID

Query to display output horizontally

I need to display a query output in a horizontal manner. I have some example data
create table TestTable (id number, name varchar2(10))
insert into TestTable values (1, 'John')
insert into TestTable values (2, 'Mckensy')
insert into TestTable values (3, 'Valneech')
insert into TestTable values (4, 'Zeebra')
commit
select * from TestTable
This gets the output in a vertical view.
ID Name
==========
1 John
2 Mckensy
3 Valneech
4 Zeebra
However, I need to display it horizontally.
ID 1 2 3 4
Name John Mckensy Valneech Zeebra
How can one do this?
To pivot, you should use the pivot clause of the select statement:
select *
from testtable
pivot ( max(name)
for id in (1,2,3,4)
)
This is not particularly pretty to do in SQL, so you should consider carefully whether this is what you want to do. I normally use Oracle Base for pivoting examples but there are many out there.
Here's a little SQL Fiddle to demonstrate.
Maybe it will help you:
select 'id', LISTAGG(id, ' ') WITHIN GROUP (ORDER BY name)
from testtable
union
select 'name', LISTAGG(name, ' ') WITHIN GROUP (ORDER BY name)
from testtable
EDIT:
or with pivot:
create table TestTable2 (id varchar2(30), name varchar2(10));
insert into TestTable2 values ('id', 'name');
insert into TestTable2
select cast(id as varchar2(30)) as id , name
from testtable
select *
from testtable2
pivot ( max(name)
for id in ('id',1,2,3,4)
)
PIVOT operator is what you are looking for.