T-sql update only when matched with joined table 1 to 1 - sql-server-2008

How can I efficiently update the table based on values from a join table
only when ID - identifier I use to join both of the tables matches perfectly
1 to 1. I mean when joined table has only one ID to the updated table?
DECLARE #T1 TABLE (
ID INT,
NAME VARCHAR(10),
Age int
)
INSERT INTO #T1 VALUES (1, 'Name', null)
DECLARE #T2 TABLE (
ID INT,
Age int
)
INSERT INTO #T2 VALUES (1, 28)
INSERT INTO #T2 VALUES (1, 29)
INSERT INTO #T2 VALUES (1, 30)
In this example table T2 has three records of the ID = 1 which corresponds to one ID
in T1.
And I would like to update T1 only when in T2 there is one record of ID = 1.
(I would like to avoid joining twice table t2 to solve this task ...)
Thanks!

;WITH T2
AS (SELECT ID,
MAX(Age) AS Age
FROM #T2
GROUP BY ID
HAVING COUNT(*) = 1)
UPDATE #T1
SET [#T1].Age = T2.Age
FROM #T1
JOIN T2
ON [#T1].ID = T2.ID

Related

UNION two tables with different columns, without duplicates, and update a field on union

I want to union two tables with the structure:
Table1: Id, Name, Reference1, Position
Table2: Id, Name, Reference2, ArtNr, Price, Position
Now to the difficult part:
All fields with different "Reference" fields must be in that new table.
The "Reference" field must be unique in the new table, so there won't be two items with the same "reference".
BUT: If there's a record with the same reference in Table 1 and Table 2, the new Record must have the "Position" of Table 1. ALL Entries that are NOT in Table 1 but in Table 2, must have a new Position with the value of [MAX(Position) increment by 1] of Table 1.
I have NO IDEA, how to solve that :)
Thanks for your help!
EDIT:
To union both:
Select Id, Name, Reference, null as ArtNr, null as Price, Position FROM Table1
Union
Select Id, Name, Reference, ArtNr, Price, Positionfrom Rechnung_Item FROM Table2
But that shows all entries of both tables...
Sample Data:
Table1:
Id:1, Name:Test, Reference: 123, Position:5
Id:2, Name:Test2, Reference: 125, Position:7
Table2:
Id:1, Name:Test, Reference1: 123, Position:1
Id:2, Name:Test3, Reference1: 127, Position:2
Desired output:
Id:1, Name:Test, Reference2: 123, Position:5
Id:2, Name:Test2, Reference2: 125, Position:7
Id:3, Name:Test3, Reference2: 127, Position:9
I tried creating sample data, it gives you result you required
declare #temp1 as table (Id int , Name varchar(50), Reference int, Position int)
insert into #temp1 (Id ,Name , Reference , Position ) values (1,'A',123,5)
insert into #temp1 (Id ,Name , Reference , Position ) values (2,'B',125,7)
--insert into #temp1 (Id ,Name , Reference , Position ) values (1,'C','Ref3',1)
declare #temp2 as table (Id int , Name varchar(50), Reference int, Position int, ArtNr int )
insert into #temp2 (Id ,Name , Reference , Position,ArtNr ) values (1,'A',123,1,1)
insert into #temp2 (Id ,Name , Reference , Position,ArtNr ) values (1,'C',127,2,2)
--insert into #temp2 (Id ,Name , Reference , Position,ArtNr ) values (1,'B',128,1,3)
--insert into #temp2 (Id ,Name , Reference , Position ,ArtNr) values (1,'C','Ref5',2,4)
select isnull(r1 ,r2) as Reference ,
ISNULL(n1,n2) as name , newPosition as Position
from (
select t1.Reference as r1 ,t2.Reference as r2 , t1.Name as n1 , t2.Name as n2 ,
case when t1.Position is not null then t1.Position else (select max(Position)+ t2.Position from #temp1)
end as newPosition
from #temp1 t1 full outer join #temp2 t2 on t1.Reference = t2.Reference
) as tr
I worked out that solution:
SELECT * FROM (
SELECT Id, Name, Reference1 as Reference, Position FROM Table1
UNION ALL
SELECT Id, Name, Reference2 as Reference, Position + (SELECT MAX(Position) FROM Table1) FROM Table2) as result GROUP BY Reference

MySql : Fetch records from multiple table by arithmetic operations

I've the following tables :
table_1
------------------
id uid category balance
1 1 A 100
2 2 B 80
table_2
------------------
id uid name
1 1 ABC
2 2 XYZ
table_2
------------------
id uid last_pay
1 1 10
2 1 10
3 1 10
4 2 80
I want to grab records from the three tables and the conditions are as follows :
a) table_1.category = something
b) ( table_1.balance - table_3.SUM(`last_pay`) ) > 0
I want the table_1.category = 'A' because (100 - (10 + 10 + 10)) > 0
Trying this query but its not working :
SELECT t1.uid,t1.category,t1.balance,t2.uid,t2.name FROM table_1 as t1
LEFT JOIN table_2 as t2 ON t1.uid = t2.uid
WHERE t1.category = 2
AND t1.balance - (SELECT SUM(`last_pay`) FROM table_3 WHERE uid = ? )
OK, I give you a full answer with normalized tables:
You can normalize the table_2 and insert the column name to table table_1. See the following and new table structure (with table_1 and table_2):
table_1
--------------------------------------------
id uid category balance name
1 1 A 100 ABC
2 2 B 80 XYZ
table_2
------------------------
id uid last_pay
1 1 10
2 1 10
3 1 10
4 2 80
To create these tables, you can use the following script:
CREATE TABLE table_1 (
`id` INT,
`uid` INT,
`category` VARCHAR(1),
`balance` INT,
`name` VARCHAR(3)
);
INSERT INTO table_1 VALUES
(1, 1, 'A', 100, 'ABC'),
(2, 2, 'B', 80, 'XYZ');
CREATE TABLE table_2 (
`id` INT,
`uid` INT,
`last_pay` INT
);
INSERT INTO table_2 VALUES
(1, 1, 10),
(2, 1, 10),
(3, 1, 10),
(4, 2, 80);
A query to get your expected result:
SELECT t1.uid, t1.category, t1.balance, t2.uid, t1.name
FROM table_1 t1
LEFT JOIN (
SELECT uid, SUM(last_pay) AS last_pay
FROM table_2
GROUP BY uid
) t2 ON t1.uid = t2.uid
WHERE (t1.balance - t2.last_pay) > 0
You can find a working example here: http://sqlfiddle.com/#!9/a2e27/3/0
You want to use your original tables? [answer for original question]
If it is possbile I recommend to normalize the tables! If it is not possible to change the table structure, you can use the following query to get your expected result:
SELECT t1.uid, t1.category, t1.balance, t2.uid, t2.name
FROM table_1 AS t1 LEFT JOIN table_2 AS t2 ON t1.uid = t2.uid
LEFT JOIN (
SELECT uid, SUM(last_pay) AS last_pay
FROM table_3
GROUP BY uid
) t3 ON t1.uid = t3.uid
WHERE (t1.balance - t3.last_pay) > 0
You can find a working example here: http://sqlfiddle.com/#!9/f22024/7/0
Create table/ insert data.
CREATE TABLE table_1
(`id` int, `uid` int, `category` varchar(1), `balance` int)
;
INSERT INTO table_1
(`id`, `uid`, `category`, `balance`)
VALUES
(1, 1, 'A', 100),
(2, 2, 'B', 80)
;
CREATE TABLE table_2
(`id` int, `uid` int, `name` varchar(3))
;
INSERT INTO table_2
(`id`, `uid`, `name`)
VALUES
(1, 1, 'ABC'),
(2, 2, 'XYZ')
;
CREATE TABLE table_3
(`id` int, `uid` int, `last_pay` int)
;
INSERT INTO table_3
(`id`, `uid`, `last_pay`)
VALUES
(1, 1, 10),
(2, 1, 10),
(3, 1, 10),
(4, 2, 80)
;
This query checks for both table_1 categories A and B
And If the table_1.balans is higher then 0 when table_3.last_pay is summed together per category
Query
SELECT
table_1.uid
, table_1.category
, table_1.balance
, table_2.uid
, table_2.name
FROM (
SELECT
uid
, SUM(table_3.last_pay) sum_last_pay
FROM
table_3
GROUP BY
table_3.uid
) AS
table_3_summed
INNER JOIN
table_1
ON
table_1.uid = table_3_summed.uid
INNER JOIN
table_2
ON
table_1.uid = table_2.uid
WHERE
(table_1.balance - table_3_summed.sum_last_pay) > 0
Result
uid category balance uid name
------ -------- ------- ------ --------
1 A 100 1 ABC

Update a column in a database table based on columns in another table

I have two tables
T1
|id|balance|
|1| 1000 |
|2| 2000 |
|3| 3000 |
T2
|id|rate|months|
|1|0.50| 10 |
|2|0.25| 24 |
|3|0.40| 16 |
I want to update the balance column in table T1 as
T1.Balance = T1.Balance + T2.rate*T2.months*T1.Balance
How can I do this in MS SQL server? Thanks!
I created temp table to recreate, so you can just use the update below:
CREATE TABLE #T1
(id INT NOT NULL,
balance money NOT NULL)
INSERT INTO #T1
(id,balance)
VALUES
(1, 1000 ),
(2, 2000 ) ,
(3, 3000 )
CREATE TABLE #T2
(id INT NOT NULL,
rate MONEY NOT NULL,
months INT NOT NULL)
INSERT #T2
(id,rate,months)
VALUES
(1,.5,10),
(2,.25,24),
(3,.4,16)
--confirm data
SELECT * FROM #T1
SELECT * FROM #T2
--update balances
update t1 SET balance = T1.Balance + (T2.rate*T2.months*T1.Balance)
FROM #T1 AS t1
JOIN #T2 AS t2
ON t1.id = t2.id
The below query can help you with updating all the rows for a particular column with a single query.
UPDATE T1 AS t1 SET t1.balance = t1.balance * (SELECT t2.rate * t2.months FROM T2 AS t2 WHERE t2.id = t1.id);
Or you can also try this one
UPDATE T1 AS t SET t.balance = (t1.balance * t2.rate * t2.months) FROM T1 AS t1 JOIN T2 AS t2 ON t1.id = t2.id;

Insert query based on number of rows

I want a query to insert a row into a table I know it is simple but the scenario is the table should not have more than 5 rows. If table has more than five rows I need to remove the old row(Or replace with new row ) (Based on the insert time stamp) then i need to insert a new row.If number of rows less than count 5 then i can directly insert a row.
Please share me the query.
How about something like this.
declare #count int
SELECT #count=COUNT(*)
from EP_ANSWERS
IF (#count<5)
// DO your insert here
ELSE
DELETE FROM TABLE
WHERE inserttimestamp = (SELECT x.inserttimestamp
FROM (SELECT MAX(t.inserttimestamp) AS inserttimestamp
FROM TABLE t) x)
// DO your insert here
If it is impossible for the table to have more than 5 rows:
DELETE FROM yourtable
WHERE 5 <= (SELECT COUNT(*) FROM yourtable)
AND yourtimestamp = (SELECT MIN(yourtimestamp) FROM yourtable)
;
INSERT INTO yourtable ...
;
If it is possible for the table to have more than 5 rows:
DELETE FROM yourtable
WHERE 5 <= (SELECT COUNT(*) FROM yourtable)
AND yourtimestamp NOT IN (SELECT yourtimestamp
FROM yourtable
ORDER BY yourtimestamp DESC
LIMIT 4)
;
INSERT INTO yourtable ...
;
It sounds like you want to put a trigger on the table to maintain this rule, in MySQL the something like this should work
CREATE TRIGGER trg__my_table__limit_rows
BEFORE INSERT
ON my_table
FOR EACH ROW
BEGIN
IF ((SELECT COUNT(1) FROM my_table) = 5)
BEGIN
DELETE FROM my_table
WHERE id = (SELECT MIN(id) FROM my_table) -- change this to fit your logic for which record should be removed
END
END
Some of the code here is in pseudo (you didn't wrote your schema), but i wrote where you need to complete your own code.
DECLARE #NumberOfRowsToInsert INT = -- select from the data you want to insert
DECLARE #MaxNumberOfRows INT = 5
DECLARE #NumberOfExistingRows INT
DECLARE #Query VARCHAR(MAX) = 'SELECT TOP #rows id FROM SomeTable ORDER BY createdDate ASC'
SELECT #NumberOfExistingRows = COUNT(*)
FROM SomeTable
SET #Query = REPLACE(#Query,'#rows',
CAST(#NumberOfRowsToInsert - (#MaxNumberOfRows - #NumberOfExistingRows))) AS VARCHAR(1))
CREATE TABLE #IdsToDelete(id INT PRIMARY KEY)
INSERT INTO #IdsToDelete
EXEC(#Query)
DELETE FROM SomeTable
WHERE id IN (SELECT * FROM #IdsToDelete)
-- insert here..

How to insert conditionally

I create a temporary table #tbl(account, last_update). I have following two inserts from different source (could be tables from different databases) to insert account with last update date. For example
create table #tbl ([account] numeric(18, 0), [last_update] datetime)
insert into #tbl(account , last_update)
select table1.account, max(table1.last_update)
from table1 join…
group by table1.account
insert into #tbl(account , last_update)
select table2.account, max(table2.last_update)
from table2 join…
group by table2.account
The problem is this could cause duplicate account in the table #tbl. I either have to avoid it during each insert or remove the duplicate after both insert. Also, if there is account with two different last_update, I want the #tbl have the latest last_update. How do I achieve this conditional insert? Which one will have better performance?
Do you think you could rewrite your query to something like:
create table #tbl ([account] numeric(18, 0), [last_update] datetime)
insert into #tbl(account , last_update)
select theaccount, MAX(theupdate) from
(
select table1.account AS theaccount, table1.last_update AS theupdate
from table1 join…
UNION ALL
select table2.account AS theaccount, table2.last_update AS theupdate
from table2 join…
) AS tmp GROUP BY theaccount
The UNION ALL will build you 1 unique table combining table1 + table2 records. From there, you can act as if was a regular table, which means that you are able to find the max last_update for each record using a "group by"
insert into #tbl(account , last_update)
select account, last_update
from
(
select a.* from #table1 a where
last_update in( select top 1 last_update from #table1 b
where
a.account = b.account
order by last_update desc)
UNION
select a.* from #table2 a where
last_update in( select top 1 last_update from #table2 b
where
a.account = b.account
order by last_update desc)
) AS tmp