SP to update 3rd table using data in first 2 tables - sql-server

For e.g. I have below table1 and table3. The 'Counts' field in table2 should be updated based on valuess field in table1 and table3. i.e. 23 appears 4 times in table1 and table3 and 45 appears once. Table2 should be updated with that count.
table1
Id | Data | Valuess
1 | rfsd | 23
2 | fghf | 45
3 | rhhh | 23
table3
Id | Data | Valuess
1 | rfsd | 23
2 | tfgy | 23
table2
Id | Fields | Counts
1 | 23 | 4
2 | 45 | 1
I am using the below stored procedure to achieve this.
WITH t13 AS (
SELECT Id, Data, Valuess FROM Table1 UNION ALL SELECT Id, Data, Valuess FROM Table3),
cte AS (SELECT Valuess,COUNT(*) AS Count2 FROM t13 GROUP BY Valuess)
UPDATE t2
SET t2.Counts = cte.Count2
FROM Table2 t2 JOIN cte ON t2.Fields = cte.Valuess;
QUESTION
Now instead of above table data, i have below table data....
table1
Id | Data | Valuess
1 | rfsd | 004561
2 | fghf | 0045614
3 | rhhh | adcwyx
table3
Id | Data | Valuess
1 | rfsd | 0045614
2 | tfgy | 004561
table2
Id | Fields | Counts
1 | 0045614 | 4
2 | adcwyxv | 1
So here we have alphanumeric data in valuess field of table1 and table3. Also we have data like '004561' and '0045614'
I want to clip off the 7th element of the field and compare it with clipping off 7th element in the table 3. i.e. 004561, 004561 and adcwyx will be taken from table1. 004561 and 004561 will be taken from table3 and compared with 004561 and adcwyx of table2 ( we need to clip off 7th element in table2 first) and then compare.
The final result should be as shown in table2.

SUBSTRING should do it.
WITH t13 AS (
SELECT Id, Data, SUBSTRING(Valuess,1,6) AS [Values]
FROM Table1
UNION ALL
SELECT Id, Data, SUBSTRING(Valuess,1,6) AS [Values]
FROM Table3
)
, cte AS (
SELECT [Values],COUNT(*) AS Count2
FROM t13 GROUP BY [Values]
)
UPDATE t2
SET t2.Counts = cte.Count2
FROM Table2 t2 JOIN cte ON SUBSTRING(t2.Fields,1,6) = cte.[Values];

Related

update column values from another table with different column name but same column value in MS SQL

update column values from another table with different column name but same column value
I have two tables as mentioned below :
Table1
ID | Name
1 | A
2 | A
3 | A
4 | A
Table2
IDX | Name
1 | XYZ
2 | PQR
3 | PPS
update Table1
set Name = (Select Name from Table2 where Table1.ID = Table2.IDX)
I'm getting below result after executing above query.
ID | Name
1 | XYZ
2 | PQR
3 | PPS
4 | NULL
But I need result as mentioned below:
ID | Name
1 | XYZ
2 | PQR
3 | PPS
4 | A
Can somebody help with this ? Thanks!
Using an update join we can try:
UPDATE t1
SET Name = t2.Name
FROM Table1 t1
INNER JOIN Table2 t2
ON t2.IDX = t1.ID;
Only records from Table1 which match to something in Table2 will be updated. This avoids the problem of making a null assignment from which your current approach suffers. You could make the following slight change to your current update to avoid the problem:
UPDATE Table1
SET Name = (SELECT COALESCE(t2.Name, Table1.Name) FROM Table2 t2
WHERE Table1.ID = t2.IDX);

sql - match two of the same values in different column positions

I am looking to join two different tables on the id, and need to extract unique names out of each table; if one table has a certain name but the other doesn't, there should be one value and one null. This should be vice versa as well.
With joins, the current output looks like this:
id name_1 name_2
1 max steph
1 max john
1 john chris
1 john chris
1 chris steph
1 chris null
1 null max
1 null null
1 tony john
1 tony max
expected output:
id name_1 name_2
1 max max
1 john john
1 chris chris
1 null steph
1 tony null
current sql:
select
table1.id,
table1.name as name_1,
table2.name as name_2
from table1
left join table2
on table1.id = table2.id
(snowflake)
SELECT
NVL(d1.id, d2.id) as id,
d1.name as name_1,
d2.name as name_2
FROM (
SELECT DISTINCT id,name FROM table1
) AS d1
FULL OUTER JOIN (
SELECT DISTINCT id,name FROM table2
) AS d2
ON d1.id = d2.id AND d1.name = d2.name
ORDER BY 1, (d1.name,d2.name)
This takes the distinct id,name pairs from both table, then full outer joins those sets of values. Thus if the id,name are in both they match. And if they don't match they are still keep.
So with these CTE's providing the fake data:
WITH table1(id,name) AS (
select * from values (1,'aa'),(1,'ab'),(2,'ba')
), table2(id,name) AS (
select * from values (1,'aa'),(1,'ac'),(2,'ba'),(2,'bb')
)
ID
NAME_1
NAME_2
1
aa
aa
1
ab
null
1
null
ac
2
ba
ba
2
null
bb
Following can be used for this -
with cte as
(
select distinct t1.id,name_1 from t1)
select distinct ifnull(t2.id,cte.id) id,
cte.name_1,
t2.name_2
from t2 full outer join cte
ON cte.id=t2.id
and cte.name_1 = t2.name_2
order by cte.name_1;
+----+--------+--------+
| ID | NAME_1 | NAME_2 |
|----+--------+--------|
| 1 | chris | chris |
| 1 | john | john |
| 1 | max | max |
| 1 | tony | NULL |
| 1 | NULL | steph |
+----+--------+--------+
Add a WHERE clause.
select
table1.id,
table1.name as name_1,
table2.name as name_2
from table1
left join table2
WHERE table1.name = table2.name
OR table1.name is null
OR table2.name is null
on table1.id = table2.id
If you just need a list of unique names
select distinct name from table1
union
select distinct name from table2
Simeons answer is the way to go since snowflake supports full outer joins. But for those of you that use a relational database that lacks support for full outer joins, and have the same issue, this approach can be an alternative:
select id,
if(instr(group_concat(tb), 1), name, NULL) name_1,
if(instr(group_concat(tb), 2), name, NULL) name_2
from(
select id, name, 1 tb from table1
union
select id, name, 2 tb from table2
) a
group by id, name
order by name
The result:
| id | name_1 | name_2 |
| --- | ------ | ------ |
| 1 | chris | chris |
| 1 | john | john |
| 1 | max | max |
| 1 | null | steph |
| 1 | tony | null |
Fake data:
CREATE TABLE table1 (
id int(11),
name varchar(50)
);
CREATE TABLE table2 (
id int(11),
name varchar(50)
);
INSERT INTO table1 VALUES
(1, 'max'),
(1, 'john'),
(1, 'chris'),
(1, 'tony');
INSERT INTO table2 VALUES
(1, 'steph'),
(1, 'john'),
(1, 'chris'),
(1, 'max');
And a dbfiddle: https://www.db-fiddle.com/f/gQ4U7hu2S2EyFEtZrapqdu/6

Split table in two tables plus a link table

I have a table with three columns with double values, but no double rows. Now I want to split this table in two table with unique values and a link table. I think the Problem gets clearer when I Show you example tables:
Original:
| ID | Column_1 | Column_2 | Column_3 |
|----|----------|----------|----------|
| 1 | A | 123 | A1 |
| 2 | A | 123 | A2 |
| 3 | B | 234 | A2 |
| 4 | C | 456 | A1 |
Table_1
| ID | Column_1 | Column_2 |
|----|----------|----------|
| 1 | A | 123 |
| 2 | B | 234 |
| 3 | C | 456 |
Table_2
| ID | Column_3 |
|----|----------|
| 1 | A1 |
| 2 | A2 |
Link-Table
| ID | fk1 | fk2 |
|----|-----|-----|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
| 4 | 3 | 1 |
Table_1 I created like this:
INSERT INTO Table_1(Column_1, Column_2)
SELECT DISTINCT Column_1, Column_2 FROM Original
WHERE Original.Column_1 NOT IN (SELECT Column_1 FROM Table_1)
Table_2 I created in the same way.
The question now is, how to create the Link-Table?
The original table does grow continuesly, so only new entries should be added.
Do I have to use a Cursor, or is there a better way?
SOLUTION:
MERGE Link_Table AS LT
USING (SELECT DISTINCT T1.ID AS T1ID, T2.ID AS T2ID FROM Original AS O
INNER JOIN Table_1 AS T1 ON T1.Column_1 = O.Column_1
INNER JOIN Table_2 AS T2 ON T2.Column_3 = O.Column_3) AS U
ON LT.fk1 = U.T1ID
WHEN NOT MATCHED THEN
INSERT (fk1, fk2)
VALUES (U.T1ID, U.T2ID);
You can JOIN all 3 tables to get proper data for link table:
--INSERT INTO [Link-Table]
SELECT t1.ID,
t2.ID
FROM Original o
INNER JOIN Table_1 t1
ON t1.Column_1 = o.Column_1
INNER JOIN Table_2 t2
ON t2.Column_3 = o.Column_3
If your original table will grow, then you need to use MERGE to update/insert new data.
You have to inner join your Original,Table_1 and Table_2 to get the desired result.
Try like this, Its similar to gofr1 post.
DECLARE #orginal TABLE (
ID INT
,Column_1 VARCHAR(10)
,Column_2 INT
,Column_3 VARCHAR(10)
)
DECLARE #Table_1 TABLE (
ID INT
,Column_1 VARCHAR(10)
,Column_2 INT
)
DECLARE #Table_2 TABLE (
ID INT
,Column_3 VARCHAR(10)
)
Insert into #orginal values
(1,'A',123,'A1')
,(2,'A',123,'A2')
,(3,'B',234,'A2')
,(4,'C',456,'A1')
Insert into #Table_1 values
(1,'A',123)
,(2,'B',234)
,(3,'C',456)
Insert into #Table_2 values
(1,'A1')
,(2,'A2')
SELECT O.ID
,T1.ID
,T2.ID
FROM #orginal O
INNER JOIN #Table_1 T1 ON T1.Column_1 = O.Column_1
INNER JOIN #Table_2 T2 ON T2.Column_3 = O.Column_3

SQL statement - join based on date

I need to write a statement joining two tables based on dates.
Table 1 contains time recording entries.
+----+-----------+--------+---------------+
| ID | Date | UserID | DESC |
+----+-----------+--------+---------------+
| 1 | 1.10.2010 | 5 | did some work |
| 2 | 1.10.2011 | 5 | did more work |
| 3 | 1.10.2012 | 4 | me too |
| 4 | 1.11.2012 | 4 | me too |
+----+-----------+--------+---------------+
Table 2 contains the position of each user in the company. The ValidFrom date is the date at which the user has been or will be promoted.
+----+-----------+--------+------------+
| ID | ValidFrom | UserID | Pos |
+----+-----------+--------+------------+
| 1 | 1.10.2009 | 5 | PM |
| 2 | 1.5.2010 | 5 | Senior PM |
| 3 | 1.10.2010 | 4 | Consultant |
+----+-----------+--------+------------+
I need a query which outputs table one with one added column which is the position of the user at the time the entry has been made. (the Date column)
All date fileds are of type date.
I hope someone can help. I tried a lot but don't get it working.
Try this using a subselect in the where clause:
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE TimeRecord
(
ID INT,
[Date] Date,
UserID INT,
Description VARCHAR(50)
)
INSERT INTO TimeRecord
VALUES (1,'2010-01-10',5,'did some work'),
(2, '2011-01-10',5,'did more work'),
(3, '2012-01-10', 4, 'me too'),
(4, '2012-11-01',4,'me too')
CREATE TABLE UserPosition
(
ID Int,
ValidFrom Date,
UserId INT,
Pos VARCHAR(50)
)
INSERT INTO UserPosition
VALUES (1, '2009-01-10', 5, 'PM'),
(2, '2010-05-01', 5, 'Senior PM'),
(3, '2010-01-10', 4, 'Consultant ')
Query 1:
SELECT TR.ID,
TR.[Date],
TR.UserId,
TR.Description,
UP.Pos
FROM TimeRecord TR
INNER JOIN UserPosition UP
ON UP.UserId = TR.UserId
WHERE UP.ValidFrom = (SELECT MAX(ValidFrom)
FROM UserPosition UP2
WHERE UP2.UserId = UP.UserID AND
UP2.ValidFrom <= TR.[Date])
Results:
| ID | Date | UserId | Description | Pos |
|----|------------|--------|---------------|-------------|
| 1 | 2010-01-10 | 5 | did some work | PM |
| 2 | 2011-01-10 | 5 | did more work | Senior PM |
| 3 | 2012-01-10 | 4 | me too | Consultant |
| 4 | 2012-11-01 | 4 | me too | Consultant |
You can do it using OUTER APPLY:
SELECT ID, [Date], UserID, [DESC], x.Pos
FROM table1 AS t1
OUTER APPLY (
SELECT TOP 1 Pos
FROM table2 AS t2
WHERE t2.UserID = t1.UserID AND t2.ValidFrom <= t1.[Date]
ORDER BY t2.ValidFrom DESC) AS x(Pos)
For every row of table1 OUTER APPLY operation fetches all table2 rows of the same user that have a ValidFrom date that is older or the same as [Date]. These rows are sorted in descending order and the most recent of these is finally returned.
Note: If no match is found by the OUTER APPLY sub-query then a NULL value is returned, meaning that no valid position exists in table2 for the corresponding record in table1.
Demo here
This works by using a rank function and subquery. I tested it with some sample data.
select sub.ID,sub.Date,sub.UserID,sub.Description,sub.Position
from(
select rank() over(partition by t1.userID order by t2.validfrom desc)
as 'rank', t1.ID as'ID',t1.Date as'Date',t1.UserID as'UserID',t1.Descr
as'Description',t2.pos as'Position', t2.validfrom as 'validfrom'
from temployee t1 inner join jobs t2 on -- replace join tables with your own table names
t1.UserID=t2.UserID
) as sub
where rank=1
This query would work
select t1.*,t2.pos from Table1 t1 left outer join Table2 t2 on
t1.Date=t2.Date and t1.UserID=t2.UserID

SELECT rows from Table1 having identical values on columns and Table2 Column > N

This is simple. I have two tables. I need to select rows from Table1 which have same 'Customer' and in Table2 'yearmm' is bigger than 2015001.
Table1
id | Customer | yearmmm |
----------------------------
10 | 123456 | 2015001 |
11 | 456789 | 2015001 |
20 | 111111 | 2015001 |
21 | 222222 | 2015001 |
44 | 4444 | 2015001 |
Table2
id | Customer | yearmmm |
----------------------------
10 | 123456 | 2015001 |
11 | 456789 | 2015002 |
20 | 111111 | 2015003 |
21 | 222222 | 2010001 |
333 | 333 | 2015004 |
Wonder if this works:
SELECT * FROM Table1 WHERE Customer IN
(SELECT Customer FROM Table2 WHERE yearmmm > '2015001')
Desired result:
11 | 456789 | 2015002 |
20 | 111111 | 2015003 |
You can use EXISTS:
SELECT t1.*
FROM Table1 t1
WHERE EXISTS
(
SELECT 1 FROM Table2 t2
WHERE t1.Customer = t2.Customer
AND t2.yearmmm > '20150101'
)
You have other options like INNER JOIN or IN.
Well, no, that will not work. You're ultimately selecting the Customer and yearmmm from Table1 based on values in Table2. Yet your desired results show yearmmm values that exist in Table2.
Based on your desired results it seems like you just want this:
SELECT * FROM Table2 WHERE yearmmm > '2015001'
EDIT: If you do in fact need more data from Table1, consider:
SELECT t1.id, t1.Customer, t2.yearmmm, another_other_fields
FROM Table1 t1 INNER JOIN Table2 t2 ON t1.id = t2.id
WHERE t2.yearmmm > '2015001'
You can use:
SELECT
t1.*
FROM
Table1 t1
INNER JOIN Table2 t2 ON
(t1.Customer = t2.Customer)
AND (t2.yearmmm > '2015001');
Or
SELECT
t1.*
FROM
Table1 t1
INNER JOIN Table2 t2 ON
(t1.Customer = t2.Customer)
WHERE
(t2.yearmmm > '2015001');

Resources