update data in table based on data in another table - sql

table1
-----------------------------
| id (int) | dt (datetime) |
-----------------------------
| 1 | 12-12-2012 |
| 2 | 13-11-2013 |
| 3 | 23-07-2014 |
| 4 | 13-06-2014 |
-----------------------------
table2
-----------------------------
| id (int) | dt2 (datetime) |
-----------------------------
| 1 | 12-12-2012 |
| 1 | 13-11-2013 | -> update table1 id=1 with this dt2
| 2 | 23-07-2014 |
| 2 | 13-06-2014 |
| 2 | 12-12-2012 | -> update table1 id=2 with this dt2
| 3 | 13-11-2013 | -> update table1 id=3 with this dt2
| 3 | 23-07-2014 |
| 3 | 13-06-2014 |
| 4 | 23-07-2014 |
| 4 | 13-02-2014 | -> update table1 id=4 with this dt2
-----------------------------
I want to update table1.dt with the corresponding dt2 from table2 based on the id.
However, I do not want to update table1.dt to the largest corresponding datetime value from table2.dt2.
I only want to update dt to the largest corresponding dt2 which is not greater than the current date.
So far what I have gotten is:
update table1
set table1.dt = table2.dt2
from table2
inner join table1 on table1.id = table2.id
where ?table1.id=table2.id and...?
No idea how to modify the sql statement such that it will only update dt to the largest corresponding dt2 which is not greater than the current date.
Hope it isn't too confusing...

Try this
UPDATE table1
SET [dbo].[Table1].dt = [dbo].[Table2].dt2
FROM [dbo].[Table2]
where [dbo].[Table2].id = [dbo].[Table1].id and [dbo].[Table2].dt2 > [dbo].[Table1].dt
and [dbo].[Table2].dt2 <= getdate()
If i'm correcting in what you're trying to achieve you are after the "where" statement that says: where id's are equal and date in Table2 is greater that what you already have in table1 and the date in table2 is less than today? then update.

You could either using group and aggregates by in your derived table there, or possibly look into cross apply. Here's an example of the former.
update table1
set table1.dt = table2.dt2
from table1 join (
select id,max(dt2) as maxDT
from table2
group by id) as derivedTable2 on derivedTable2 .id = table1.id

Something like this construct would work:
UPDATE table1
SET dt = dt2
FROM ( SELECT id AS _id ,
MAX(dt2) AS dt2
FROM ( SELECT T2.id ,
T2.dt2
FROM Table1 T1
INNER JOIN Table2 T2 ON T1.id = T2.id
WHERE T2.dt2 < T1.dt
) A
GROUP BY id
) B
WHERE id = _id;

Related

SQL query join- unrelated tables

Can someone help me to join the two tables without any primary or secondary keys. Sample table is
TABLE 1
| ID | NAME |
| 1 | x |
| 2 | Y |
| 3 | z |
TABLE 2
| Num | NAME | DATE |
| 52 | X | 12-aug-17 |
| 53 | X | 11-apr-17 |
| 62 | X | 10-aug-11 |
| 12 | y | 2-jan-16 |
| 23 | Y | 3-apr-18 |
I want retrieve data from X
select *
from table2
where name = 'x';
| Num | NAME | DATE |
| 52 | X | 12-aug-17 |
| 53 | X | 11-apr-17 |
| 62 | X | 10-aug-11 |
Now I will get three data from table2. I'm little stuck after this step. I want to get top of data the from table 2 and combine with table one.
I want final output should be
| ID | NAME | Num | DATE |
| 1 | x | 52 | 12-aug-17 |
Can someone suggest me how can I join this table? Its easy to join when we have any primary key but here not the case
Thanks
You can use this:
SELECT TOP(1) table1.ID, table2.Num, table2.Name, table2.DATE
FROM table2 INNER JOIN table1 ON table1.NAME = table2.NAME
WHERE table2.NAME = 'x'
ORDER BY table2.DATE ASC
OR
SELECT table1.ID, table2.Num, table2.Name, table2.DATE
FROM table1 INNER JOIN
(SELECT TOP(1) * FROM table2 WHERE NAME = 'x' ORDER BY DATE ASC) table2
ON table1.NAME = table2.NAME
You need to get the maximum DATE using a subquery, as in:
select t1.id, t2.*
from table1 t1
join table2 t2 on t2.name = t1.name
where t2.date = (
select max(date) from table2 where name = 'x'
);

How to count the number of values in a table with 2 columns as the parameter on SQL Server?

I have 2 tables, where the values are as follow:
Table A:
| Date | Time | Count |
===============================================
| D1 | T1 | 0 |
| D1 | T2 | 0 |
| D2 | T1 | 0 |
| D2 | T2 | 0 |
Table B:
| Date | Time | Value |
===============================================
| D1 | T1 | a |
| D1 | T1 | b |
| D1 | T1 | c |
| D1 | T2 | e |
| D2 | T1 | f |
| D2 | T1 | g |
| D2 | T1 | h |
| D2 | T2 | i |
| D2 | T2 | j |
I'm trying to create a query that could count the number of Value from Table B and insert the result into the column Count of Table A
Where the result should show (on Table A):
| Date | Time | Count |
===============================================
| D1 | T1 | 3 |
| D1 | T2 | 1 |
| D2 | T1 | 3 |
| D2 | T2 | 2 |
I tried using normal UPDATE with the code:
UPDATE A
SET Count = (SELECT COUNT(Value)
FROM B, A
WHERE A.Date = B.Date
and A.Time = B.Time)
However, it resulted in all Count becoming 9 instead of showing each Date and Time set its value
I couldn't create an ID for each Date and Time data, as the values of the column Date and Time will change each hours
Is there something wrong with my code or is there any other way to approach this?
Thank you in advance for any help provided
The main problem with your SQL is it does not distinguish between rows - it simply updates all of them to a single calculated value. You need to join the table you're updating back to the source - which is this case is a grouped version of tableB.
This should do it
UPDATE tableA
SET Count = b.Count
FROM tableA a
INNER JOIN
(
SELECT Date, Time, COUNT(value) as Count
FROM tableB
GROUP BY Date,Time
) b
ON a.Date = b.Date AND a.Time=b.Time
Live demo: http://sqlfiddle.com/#!18/7264f/2
You can use a JOIN. But the second table should be with the count of [Value] as a sub-query.
Query
update t1
set [t1].[Count] = [t2].[Count]
from [TableA] as [t1]
join (
select [Date], [Time], count([Value]) as [Count]
from [TableB]
group by [Date], [Time]
) as [t2]
on [t1].[Date] = [t2].[Date]
and [t1].[Time] = [t2].[Time];
The query you are using:
UPDATE A
SET Count = (SELECT COUNT(Value)
FROM B, A --<-- A being used here overrides `A` of `UPDATE`
WHERE A.Date = B.Date
and A.Time = B.Time)
uses a subquery to update A rows. The subquery applies COUNT to a list of joined rows between A and B. So, COUNT returns always the same value for every row of A that is updated.
The original query posted, i.e. the one before the edit was made in the OP, was correct:
UPDATE A
SET Count = (SELECT COUNT(Value)
FROM B
WHERE A.Date = B.Date
and A.Time = B.Time)
In this query there is a correlation between the row being updated and all rows from B, based on the condition:
A.Date = B.Date and A.Time = B.Time
Hence, the value returned by the subquery is dependent upon Date and Time fields of every single row being update.
Demo here

Get Last Row or Smallest data then join two tables

Using this Question where it is related Get Last Row of Different id then display data that is greater than zero
I would like to join another table
This is my table2
+----+--------+
| id | name |
+----+--------+
| 1 | Taylor |
| 2 | Zac |
| 3 | Scott |
| 4 | Emma |
+----+--------+
If I use this code...
SELECT DISTINCT t1.id, t1.amount, t2.name FROM table1 t1, table2 t2 WHERE t1.amount = (SELECT MIN(t1.amount) FROM table1 WHERE id= t1.id) AND t1.[t1.amount]>0 AND t1.[id]=t2.[id];
... then these result show...
+----+--------+-------+
| id | amount | name |
+----+--------+-------+
| 2 | 100 | Zac |
+----+--------+-------+
only 1 data is showing
what i want is both data in the table
+----+--------+-------+
| id | amount | name |
+----+--------+-------+
| 2 | 100 | Zac |
| 4 | 200 | Emma |
+----+--------+-------+
SELECT DISTINCT t.id,t2.name,t.amount
FROM table t
INNER JOIN table2 t2 ON t.id=t2.id
WHERE amount = (SELECT MIN(amount) FROM table WHERE id= t.id)
and amount>0;
Believe you're looking for a subquery of the first table, try the following:
SELECT DISTINCT t1.id, t1.amount, t2.name
FROM (SELECT DISTINCT id, amount FROM table t
WHERE amount = (SELECT MIN(amount) FROM table WHERE id= t.id)
and amount>0) t1, table2 t2
WHERE t1.[id]=t2.[id];
Not sure why your current query isn't working but hope this helps!
Please try the following...
SELECT table2.id AS id,
minAmount AS amount,
name
FROM ( SELECT id,
MIN( amount ) AS minAmount
FROM table1
GROUP BY id
HAVING MIN( amount ) > 0
) AS table1Refiner
INNER JOIN table2 ON table1Refiner.id = table2.id;
This statement works by obtaining the results as per your first Question and joining them to table2 based on their shared values of id, effectively appending the corresponding name to each id and amount. The fields are then selected and output.
If you have any questions or comments, then please feel free to post a Comment accordingly.

SQL Query to Bring Back where Row Count is Greater than 1

I have two tables.They have the same data but from different sources. I would like to find all columns from both tables that where id in table 2 occurs more than once in table 1. Another way to look at it is if table2.id occurs only once in table1.id dont bring it back.
I have been thinking it would be some combination of group by and order by clause that can get this done but its not getting the right results. How would you express this in a SQL query?
Table1
| id | info | state | date |
| 1 | 123 | TX | 12-DEC-09 |
| 1 | 123 | NM | 12-DEC-09 |
| 2 | 789 | NY | 14-DEC-09 |
Table2
| id | info | state | date |
| 1 | 789 | TX | 14-DEC-09 |
| 2 | 789 | NY | 14-DEC-09 |
Output
|table2.id| table2.info | table2.state| table2.date|table1.id|table1.info|table1.state|table1.date|
| 1 | 789 | TX | 14-DEC-09 | 1 | 123 | TX | 12-DEC-09 |
| 1 | 789 | TX | 14-DEC-09 || 1 | 123 | NM | 12-DEC-09 |
If you using MSSQL try using a Common Table Expression
WITH cte AS (SELECT T1.ID, COUNT(*) as Num FROM Table1 T1
INNER JOIN Table2 T2 ON T1.ID = T2.ID
GROUP BY T1.ID
HAVING COUNT(*) > 1)
SELECT * FROM cte
INNER JOIN Table1 T1 ON cte.ID = T1.ID
INNER JOIN Table2 T2 ON cte.ID = T2.ID
First, I would suggest adding an auto-incrementing column to your tables to make queries like this much easier to write (you still keep your ID as you have it now for relational-mapping). For example:
Table 1:
TableID int
ID int
Info int
State varchar
Date date
Table 2:
TableID int
ID int
Info int
State varchar
Date date
Then your query would be really easy, no need to group, use CTEs, or row_over partitioning:
SELECT *
FROM Table2 T2
JOIN Table1 T1
ON T2.ID = T1.ID
JOIN Table1 T1Duplicate
ON T2.ID = ID
AND T1.TableID <> T1Duplicate.TableID
It's a lot easier to read. Furthermore, there are lots of scenarios where an auto-incrementing ID field is benefitial.
I find this a much simpler way to do it:
select TableA.*,TableB.*
from TableA
inner join TableB
on TableA.id=TableB.id
where TableA.id in
(select distinct id
from TableA
group by id
having count(*) > 1)

Update column with value from another table using SQLite?

I have two SQLite tables. I want to update a column in table1 with a value from table2.
Table 1, table1 (id INTEGER AUTOINCREMENT, status TEXT, name TEXT);:
| id | status | name |
|----|-----------|------|
| 1 | pending | xyz |
| 2 | completed | abc |
Table 2, table2 (status TEXT, name TEXT, trans_id INTEGER);:
| trans_id | status | name |
|----------|-----------|------|
| 1 | refunded | cvb |
| 2 | cancelled | asd |
I want to update status and name from table2 to table1 where table1.id = table2.trans_id. I have this query:
UPDATE table1
SET status = (SELECT t2.status FROM table1 t1,table2 t2 WHERE t1.id = t2.trans_id) ,
name = (SELECT t2.name FROM table1 t1,table2 t2 WHERE t1.id = t2.trans_id)
WHERE id IN (SELECT trans_id FROM table1 t1,table2 t2 WHERE t1.id = t2.trans_id)
It populates table1 wrongly. This is the resultant table1
| id | status | name |
|----|----------|------|
| 1 | refunded | cvb |
| 2 | refunded | cvb |
My requirement is this:
| id | status | name |
|----|-----------|------|
| 1 | refunded | cvb |
| 2 | cancelled | asd |
Whats wrong with my query? How can I achieve it?
I am assuming that the t2.trans_id is uniq or primary key in table2. If not then if it return multiple result then the update query will blow up. In that case either you need to apply the more filter using the WHERE or use the TOP 1 if any result will be needed.
UPDATE table1
SET status = (SELECT t2.status FROM table2 t2 WHERE t2.trans_id = id) ,
name = (SELECT t2.name FROM table2 t2 WHERE t2.trans_id = id)
WHERE id IN (SELECT trans_id FROM table2 t2 WHERE t2.trans_id= id)
The previous answer will be failed if there is the id column in the table2. It would be better that using the full name table1.id
UPDATE table1
SET status = (SELECT t2.status FROM table2 t2 WHERE t2.trans_id = table1.id) ,
name = (SELECT t2.name FROM table2 t2 WHERE t2.trans_id = table1.id)
WHERE id IN (SELECT trans_id FROM table2 t2 WHERE t2.trans_id= table1.id);