Check if entry of one table is in another one - sql

I have two SQL Server tables.
First is filled with languagecodes (e.g. en, de, fr,..).
Second looks like:
ID | Lang | Text
----------------
..1..|..en..|..one..
..1..|..de..|..eins..
..1..|..fr..|..une..
..2..|..en..|..two..
..2..|..de..|..zwei..
Now what I want is to go trough the seconde table over every ID, check if there is a row for every language and if not add a empty row. So for the example above the second table will have an additional row:
..2..|..fr..|.. ..
Is there any way to realize this in SQL Server?

This whould be basic join question if you have ID at first table so the code is:
declare #tabLanguages table (id int,Lang char(2))
insert into #tabLanguages
values (1,'en'),(2,'de'),(3,'fr')
declare #Translation table (id int, Lang char(2), Text nvarchar(200))
insert into #Translation
values
(1,'en','one'),
(1,'de','eins'),
(1,'fr','.une'),
(2,'en','two'),
(2,'de','zwei')
select isnull(t.id,l.Id) as ID,
isnull(t.Lang,l.Lang) as Lang,
t.Text
from #tabLanguages l
left outer join #Translation t on l.id = t.Id
order by Id
But if you don't have Id in the first table then you can use following:
declare #tabLanguages table (Lang char(2))
insert into #tabLanguages
values ('en'),('de'),('fr')
declare #Translation table (id int, Lang char(2), Text nvarchar(200))
insert into #Translation
values
(1,'en','one'),
(1,'de','eins'),
(1,'fr','.une'),
(2,'en','two'),
(2,'de','zwei')
select isnull(t.id,l.Id) as ID,
isnull(t.Lang,l.Lang) as Lang,
t.Text
from (
select *, row_number() over (order by Lang) as Id
from #tabLanguages t
) l
left outer join #Translation t on l.id = t.Id
order by l.Id

Related

How to split String after CONCAT over the repetition of Row Number

I have 2 tables as shown:
I want to CONCAT the two tables by joining them and split them over the repetition of Row Number.
CREATE TABLE #portiontable (
PortionKey NVARCHAR(100),
RN INT,
)
CREATE TABLE #finaltable (
Value NVARCHAR(100),
RN INT,
)
INSERT INTO #finaltable (Value,RN)
VALUES ('KRM__21X0E',1),
('C',2),
('',3),
('',4),
('KRM__21X0E',1),
('C',2),
('',3),
('',4)
INSERT INTO #portiontable (PortionKey,RN)
VALUES ('100',1),
('0AD',2),
('D',3)
SELECT * FROM #finaltable f
SELECT * FROM #portiontable p
SELECT (SELECT ''+ ValuePortionKey
FROM (
SELECT f.RN,f.value,P.PortionKey, f.value + P.PortionKey AS ValuePortionKey
FROM #portiontable p
INNER JOIN #finaltable f ON p.rn = f.rn
) ft
FOR XML PATH('')) as PartSignature
DROP TABLE #portiontable
DROP TABLE #finaltable
The desired output is 2 rows:
PartSignature
KRM__21X0E100C0ADD
KRM__21X0J100K0ADD
The actual output is:
PartSignature
KRM__21X0E100C0ADDKRM__21X0J100K0ADD
Firstly, it seems that you have 2 sets of data in the #finaltable. You need another column to identify it as a set. I have added a ValueSet in the #finaltable.
And, I think your sample data does not correspond to the expected output. I have amended the sample data for #finaltable
And finally, using STRING_AGG to perform the string concatenation, you can then GROUP BY the new ValueSet
CREATE TABLE #portiontable
(
PortionKey NVARCHAR(100),
RN INT,
)
CREATE TABLE #finaltable
(
ValueSet INT,
Value NVARCHAR(100),
RN INT,
)
INSERT INTO #portiontable (PortionKey,RN)
VALUES ('100',1),
('0AD',2),
('D',3)
INSERT INTO #finaltable (ValueSet,Value,RN)
VALUES (1,'KRM__21X0E',1),
(1,'C',2),
(1,'',3),
(1,'',4),
(2,'KRM__21X0J',1),
(2,'K',2),
(2,'',3),
(2,'',4)
SELECT f.ValueSet,
STRING_AGG (f.Value + p.PortionKey, '') AS ValuePortionKey
FROM #portiontable p
INNER JOIN #finaltable f ON p.RN = f.RN
GROUP BY f.ValueSet
DROP TABLE #portiontable
DROP TABLE #finaltable
-- Result
1 KRM__21X0E100C0ADD
2 KRM__21X0J100K0ADD

I need to migrate data from one old table to a new table by storing appropriate CityId instead CityName

I'm migrating data from one table to another table in SQL Server, In this process what I need to do is "I have 10 columns in old table one column is 'CityName' which is varchar and in the new table, I have a column 'CityId' which is an integer. And I have other table which has data about city id and names. I need store the appropriate cityId in new table instead of CityName. Please help me. Thanks in advance.
You'll need to join the source table to the CityName field in the city information table:
INSERT INTO dbo.Destination (CityID, OtherStuff)
SELECT t1.CityID, t2.OtherStuff
FROM CityInformationTable t1
INNER JOIN SourceTable t2
ON t1.CityName = t2.CityName
Below should give you an idea, you need to inner join to your look up table to achieve this.
declare #t_cities table (Id int, City nvarchar(20))
insert into #t_cities
(Id, City)
values
(1, 'London'),
(2, 'Dublin'),
(3, 'Paris'),
(4, 'Berlin')
declare #t table (City nvarchar(20), SomeColumn nvarchar(10))
insert into #t
values
('London', 'AaaLon'),
('Paris', 'BeePar'),
('Berlin', 'CeeBer'),
('London', 'DeeLon'),
('Dublin', 'EeeDub')
declare #finalTable table (Id int, SomeColumn nvarchar(10))
insert into #finalTable
select c.Id, t.SomeColumn
from #t t
join #t_cities c on c.City = t.City
select * from #finalTable
Output:
Id SomeColumn
1 AaaLon
3 BeePar
4 CeeBer
1 DeeLon
2 EeeDub

Find and insert dummy rows - possible scenario for OUTER APPLY

This is a mock up of the situation we've got:
IF OBJECT_ID('TEMPDB..#People') IS NOT NULL BEGIN DROP TABLE #People END;
CREATE TABLE #People
(
Name VARCHAR(100),
Category VARCHAR(20),
ID INT
);
INSERT INTO #People
values
('x','Bronze',1),
('y','Bronze',2),
('z','Silver',3),
('j','Gold',4),
('q','Bronze',5),
('x','Silver',1);
IF OBJECT_ID('TEMPDB..#Category') IS NOT NULL BEGIN DROP TABLE #Category END;
CREATE TABLE #Category
(
Category VARCHAR(100)
);
INSERT INTO #Category
values
('Gold'),
('Silver'),
('Bronze');
If a name does not have a Category e.g. x does not have Gold then I'd like a row creating and adding into the table #People with an ID of -1.
Current solution I have is this:
WITH x AS
(
SELECT DISTINCT
x.Name,
s.Category
FROM #People x
CROSS JOIN #Category s
)
INSERT INTO #People
SELECT J.Name,
J.Category,
ID = -1
FROM x J
WHERE NOT EXISTS
(
SELECT 1
FROM #People Q
WHERE J.Name = Q.Name
AND J.Category = Q.Category
);
See it works!...:
SELECT *
FROM #People;
I have a feeling CROSS APPLY might be a good operator to use in order to simplify the above - What is the simplest way to find, create and insert these rows?
insert into People(Name, Category, Id)
(
select distinct
p.Name,
c.Category,
p.Id
from
people p
cross join category c
where
Concat(p.id, c.Category) not in (select Concat(id, Category) from people)
);
http://www.sqlfiddle.com/#!6/92cd5/14

SQL select -one to many joins want to have the manys

I have two tables, TBL_PARENT (parentID, ParentName) and TBL_CHILDREN (ParentID,Child_Name)
A Parent can have 0 to many children
What I want is a query to give me a list of parent and their children in single row per parent.
For example
Parent1 John,Mary
Parent2 jane,steve,jana
And the number of rows to be the total number of parents
try this query :
I have created 3 table 2 of them are already created on your database #parant, #ch
and the third one is a temp table to put the result in.
create table #parant (id int , name varchar(10))
create table #ch (id int , name varchar(10), pid int)
insert into #parant select 1,'PA'
insert into #parant select 2,'PB'
insert into #parant select 3,'PC'
insert into #ch select 1,'Ca',1
insert into #ch select 1,'Cb',1
insert into #ch select 1,'Cc',1
insert into #ch select 1,'Cd',3
insert into #ch select 1,'Cf',3
insert into #ch select 1,'Ch',1
create table #testTable (id int, name varchar(10),chid int, chname varchar(10), cpid int)
insert into #testTable
select x.id , x.name ,isnull( y.id ,0), isnull(y.name,'') ,isnull(y.pid ,0)
from #parant as x
left outer join #ch as y
on x .id = y .pid
SELECT t.ID, t.name , STUFF(
(SELECT ',' + s.chname
FROM #TestTable s
WHERE s.ID = t.ID
FOR XML PATH('')),1,1,'') AS CSV
FROM #TestTable AS t
GROUP BY t.ID, t.name
GO
drop table #testTable
drop table #ch
drop table #parant
for the above data i got the following result
1 PA Ca,Cb,Cc,Ch
2 PB
3 PC Cd,Cf
SELECT COUNT(P.parentID),
P.ParentName,
C.Child_Name
FROM TBL_PARENT as P
INNER JOIN TBL_CHILDREN as C
WHERE P.parentID == c.ParentID
GROUP BY P.ParentName;
The line P.parentID == c.ParentID is doing the Join, and the line count(P.parentID) is doing the count of all the parents and the line GROUP BY P.ParentName is grouping all the rows by the name of the parent so you can display all the children of every single parent.

What the best way to get values in multiple rows and set variables with out cursors in SQL Server? (PIVOT more or less)

I could not think of a better question for the problem, but here it is.
I have 3 tables in a many to many relationship like:
Students -> StudentTasks <- Tasks
The student task has a column called "Marked", and when a student is created a create a record for possible tasks and Marked = 0, Ex:
Student ---------
Given
"StudentA -> Id = 1"
Tasks ------------
Given
"Task A -> Id = 1"
"Task B -> Id = 2"
StudentTasks ------
StudentId -- TaskId -- Marked
1 -- 1 -- 0
1 -- 2 -- 0
What I need is for each row in student task I have to set variable #TaskA, #TaskB
with the respective "Marked" value, so I can update another table's column with it.
Another way to solve the problem would be to update the table directly, so given the same scenario, but with the addition of a table like so:
StudentId -- TaskA -- TaskB
I would like to see it filled like this:
StudentId -- TaskA -- TaskB
1 -- 0 -- 0
and if we had "StudentB -< Id = 2" with TaskB marked a 1 we would have:
StudentId -- TaskA -- TaskB
1 -- 0 -- 0
2 -- 0 -- 1
The way I am doing is not efficient at all, its taking 40 seconds to go through 3300 records (I am using cursors to walk through the list of students), any suggestions are welcome.
UPDATES:
Using the idea #djangojazz did with the self extracting queries
DECLARE #Student TABLE ( StudentID INT IDENTITY, Name VARCHAR(50));
INSERT INTO #Student VALUES ('Brett'),('Sean')
DECLARE #StudentTasks TABLE (StudentID INT, TaskId INT, Marked BIT);
INSERT INTO #StudentTasks VALUES (1,1,0),(1,2,0),(2,1,0),(2,2,1)
DECLARE #Tasks TABLE (TaskID INT IDENTITY, NAME VARCHAR(50));
INSERT INTO #Tasks VALUES ('Study'),('Do Test')
SELECT * FROM #Student
SELECT * FROM #StudentTasks
SELECT * FROM #Tasks
-- THIS IS WHAT I NEED IN THE RESULT
DECLARE #ResultTable TABLE (StudentId INT, Study BIT, DoTest BIT);
INSERT INTO #ResultTable VALUES (1,0,0),(2,0,1)
SELECT * FROM #ResultTable
UPDATED 6-13-13. I don't even think you need the 'Students' table right off the bat as you just want to pivot on the identifier. The problem may become though if you use repeat values for anything in the future this logic will break. Meaning if you have a table where a Student Id may be repeated for another value with a type other than bit you would then need to perform more operations to see which was the most current by an identity or such. Saying that though I can give you what you say you wanted.
DECLARE #Student TABLE ( StudentID INT IDENTITY, Name VARCHAR(50));
INSERT INTO #Student VALUES ('Brett'),('Sean')
DECLARE #StudentTasks TABLE (StudentID INT, TaskId INT, Marked BIT);
INSERT INTO #StudentTasks VALUES (1,1,0),(1,2,0),(2,1,0),(2,2,1)
DECLARE #Tasks TABLE (TaskID INT IDENTITY, NAME VARCHAR(50));
INSERT INTO #Tasks VALUES ('Study'),('Do Test')
DECLARE #ResultTable TABLE (StudentId INT, Study BIT, DoTest BIT);
INSERT INTO #ResultTable VALUES (1,0,0),(2,0,1)
select 'Results you wanted'
SELECT *
FROM #ResultTable
select 'Method A'
;
-- with case when forcing a pivot on an expression
With x as
(
select
st.StudentID
, cast(st.Marked as tinyint) as Marked
, t.NAME
from #StudentTasks st
join #Tasks t on st.TaskId = t.TaskID
)
Select
x.StudentID
, max(case when NAME = 'Study' then Marked end) as Study
, max(case when NAME = 'Do Test' then Marked end) as DoTest
FROM x
group by x.StudentID
Select 'Method B'
;
-- with traditional pivot you need to translate names I believe
With x as
(
select
st.StudentID
, cast(st.Marked as tinyint) as Marked
, case when t.NAME = 'Study' then 0 else 1 end as Name
from #StudentTasks st
join #Tasks t on st.TaskId = t.TaskID
)
Select
pvt.StudentID
, [0] as Study
, [1] as 'Do Test'
FROM x
pivot(max(x.Marked) for x.Name in ([0], [1])) as pvt
PIVOT the StudentTasks table for the 2 Tasks - A and B, JOIN it with the 'Additional table' on StudentID and Update it ..