SQL insert/update to a table from another table based on some condition - sql

I have a table like below named table1:
+-----------+-------+
| productid | stock |
+-----------+-------+
| 1 | 10 |
| 2 | 20 |
| 3 | 30 |
+-----------+-------+
I need to insert / update to the above table from another table named table2:
+-----+-------+
| PId | stock |
+-----+-------+
| 1 | 20 |
| 2 | 40 |
| 4 | 10 |
+-----+-------+
I would like to execute an SQL query with below condition:
if PId from table2 exist in Productid in table1 then need to update the value of stock.
if PId from table2 doesnt exist in Productid in table1 then need to insert the value of stock as a new row in table1 from table2.
So after executing query output in table1 would be like below:
+-----------+-------+
| productid | stock |
+-----------+-------+
| 1 | 20 |
| 2 | 40 |
| 3 | 30 |
| 4 | 10 |
+-----------+-------+
Help me to get the query as I am new to SQL. Thanks in advance!

You want a MERGE statement. Most database management systems support it nowadays:
MERGE INTO table1
USING table2
ON table1.productid=table2.pid
WHEN MATCHED THEN UPDATE SET
stock = table2.stock
WHEN NOT MATCHED THEN INSERT VALUES (
table2.pid
, table2.stock
)
;
SELECT * FROM table1 ORDER BY 1;
-- out OUTPUT
-- out --------
-- out 3
-- out (1 row)
-- out
-- out Time: First fetch (1 row): 27.090 ms. All rows formatted: 27.155 ms
-- out productid | stock
-- out -----------+-------
-- out 1 | 20
-- out 2 | 40
-- out 3 | 30
-- out 4 | 10

Related

How to join two tables with sum of one column and with condition

I have two tables:
table 1
+-------------+--------------+-----------------+
| id_product | id_customer |start_date |
+-------------+--------------+-----------------+
| 1 | 1 | 2021-08-28T10:37|
| 1 | 2 | 2021-08-28T11:17|
| 1 | 3 | 2021-08-28T12:27|
| 2 | 1 | 2021-08-28T17:00|
table 2
+-------------+------------------+----------+-------------------------------+
| id_customer | stop_date | duration | 20 other columns like duration|
+-------------+------------------+----------+-------------------------------+
| 1 | 2021-08-27T17:00| 20 | ...
| 1 | 2021-08-26T17:00| 40 | ...
| 2 | 2021-08-29T17:00| 120 | ...
| 1 | 2021-08-30T17:00| 40 | ...
| ..........................................|
start_date in table 1 is the date the customer started the product.
stop_datein table 2 is the date the customer stopped the product.
I want to join these two tables to have something like : one row with :
productid
customer_id
start_date
sum of all duration for all the stop_date BEFORE start_date.
same as duration for all the 20 reminding columns.
example for product_id = 1, custom_id = 1 :
+-------------+--------------+-----------------+---------------+-----------------------------------+
| id_product | id_customer |start_date | sum(duration) | sum(all other columns from table 2)
+-------------+--------------+-----------------+---------------+-----------------------------------+
| 1 | 1 | 2021-08-28T10:37| 60
I have a really big tables, I am using pyspark with SQL. Do you know an optimised way to this ?
Thank you
EDIT :
There is also an id_product in table2
SELECT
Table_1.id_product,
Table_1.id_customer,
Table_1.start_date,
SUM(duration) AS [sum(duration)]
---,SUM(duration2)
---,SUM(duration3)
FROM Table_1
LEFT JOIN Table_2 ON
Table_2.id_customer = Table_1.id_customer
AND Table_2.id_product = Table_1.id_product
AND Table_2.stop_date < Table_1.start_date
GROUP BY Table_1.id_product,Table_1.id_customer, Table_1.start_date

How to select timestamp values in PostgreSQL under conditions?

I have a database table 'table1' as follows:
f_key | begin | counts|
1 | 2018-10-04 | 15 |
1 | 2018-10-06 | 20 |
1 | 2018-10-08 | 34 |
1 | 2018-10-09 | 56 |
I have another database table 'table2' as follows:
f_key | p_time | percent|
1 | 2018-10-05 | 80 |
1 | 2018-10-07 | 90 |
1 | 2018-10-08 | 70 |
1 | 2018-10-10 | 60 |
The tables can be joined by the f_key field.
I want to get a combined table as shown below:
If the begin time is earlier than any of the p_time then the p_time value in the combined table would be the same as begin time and the percent value would be 50. (As shown in row 1 in the following table)
If the begin time is later than any of the p_time then the p_time value in the combined table would be the very next available p_time and the percent value would be the corresponding value of the selected p_time.
(As shown in row 2, 3 and 4 in the following table)
row | f_key | begin | counts| p_time | percent|
1 | 1 | 2018-10-04 | 15 | 2018-10-04 | 50 |
2 | 1 | 2018-10-06 | 20 | 2018-10-05 | 80 |
3 | 1 | 2018-10-08 | 34 | 2018-10-07 | 90 |
4 | 1 | 2018-10-09 | 56 | 2018-10-08 | 70 |
You can try to use row_number window function to make row number which is the closest row from table1 by begin.
then use coalesce function to let begin time is earlier than any of the p_time then the p_time value in the combined table would be the same as begin time and the percent value would be 50
PostgreSQL 9.6 Schema Setup:
CREATE TABLE table1(
f_key INT,
begin DATE,
counts INT
);
INSERT INTO table1 VALUES (1,'2018-10-04',15);
INSERT INTO table1 VALUES (1,'2018-10-06',20);
INSERT INTO table1 VALUES (1,'2018-10-08',34);
INSERT INTO table1 VALUES (1,'2018-10-09',56);
CREATE TABLE table2(
f_key INT,
p_time DATE,
percent INT
);
INSERT INTO table2 VALUES (1, '2018-10-05',80);
INSERT INTO table2 VALUES (1, '2018-10-07',90);
INSERT INTO table2 VALUES (1, '2018-10-08',70);
INSERT INTO table2 VALUES (1, '2018-10-10',60);
Query 1:
SELECT ROW_NUMBER() OVER(ORDER BY begin) "row",
t1.f_key,
t1.counts,
coalesce(t1.p_time,t1.begin) p_time,
coalesce(t1.percent,50) percent
FROM (
SELECT ROW_NUMBER() OVER(PARTITION BY t1.begin,t1.f_key order by t2.p_time desc) rn,
t2.p_time,
t2.percent,
t1.counts,
t1.f_key,
t1.begin
FROM table1 t1
LEFT JOIN table2 t2 ON t1.f_key = t2.f_key and t1.begin > t2.p_time
)t1
WHERE rn = 1
Results:
| row | f_key | counts | p_time | percent |
|-----|-------|--------|------------|---------|
| 1 | 1 | 15 | 2018-10-04 | 50 |
| 2 | 1 | 20 | 2018-10-05 | 80 |
| 3 | 1 | 34 | 2018-10-07 | 90 |
| 4 | 1 | 56 | 2018-10-08 | 70 |

SQL Server: most efficient way to update multiple records depending on each other

I want to update multiple records from table "a" depending on each other. The values of the table "a" look like:
+------------+---------------+-------+
| date | transfervalue | value |
+------------+---------------+-------+
| 01.03.2018 | 0 | 10 |
| 02.03.2018 | 0 | 6 |
| 03.03.2018 | 0 | 13 |
+------------+---------------+-------+
After the update the values of the table "a" should look like:
+------------+---------------+-------+
| date | transfervalue | value |
+------------+---------------+-------+
| 01.03.2018 | 0 | 10 |
| 02.03.2018 | 10 | 6 |
| 03.03.2018 | 16 | 13 |
+------------+---------------+-------+
What is the most efficient way to do this? I've tried three different solutions, but the last solution doesn't work.
Solution 1: do a loop and iterate over each day to do the update statement
Solution 2: do an update statement statement for each day
Solution 3: do the update for the whole timespan in one statement
The output of solution 3 was:
+------------+---------------+-------+
| date | transfervalue | value |
+------------+---------------+-------+
| 01.03.2018 | 0 | 10 |
| 02.03.2018 | 10 | 6 |
| 03.03.2018 | 6 | 13 |
+------------+---------------+-------+
You seem to want a cumulative sum:
with toupdate as (
select t.*, sum(value) over (order by date rows between unbounded preceding and 1 preceding) as running_value
from t
)
update toupdate
set transfervalue = coalesce(running_value, 0);
This should work:
select t1.*,
coalesce((select sum(value) from table1 t2 where t2.date < t1.date), 0) MyNewValue
from table1 t1

Sql view from multiple tables

I am stuck in a query, please help.
I want to create view.
Table1
ID | Acode | Bcode | Ccode |
1 | 10 | 101 | 102 |
2 | 11 | 100 | 101 |
3 | 10 | 100 | 102 |
Table2
Acode | Adescription |
10 | English |
11 | Math |
Table3
Bcode | Bdescription |
100 | Grade A |
101 | Grade B |
Table4
Ccode | Cdescription |
100 | Level A |
101 | Level B |
102 | Level C |
I want to print all rows in Table1 with description from other tables based on code in table1.
Output should be:
data
NewView
ID | Acode |Adescription | Bcode | Bdescription | Ccode | Cdescription |
1 | 10 | English | 101 | Grade B | 102 | Level C |
2 | 11 | Math | 100 | Grade A | 101 | Level B |
3 | 10 | English | 100 | Grade A | 102 | Level C |
I created left join but it returns more rows than actual in table1. I want to have only all records from table1 with description from other tables.
Please help
Below is an example. Since you didn't post your original query attempt, we can't really say why you were getting multiple rows. No need for a LEFT JOIN unless you are missing codes in the joined tables.
SELECT Table1.ID
, Table1.Acode
, Table2.Adescription
, Table1.Bcode
, Table3.Bdescription
, Table1.Ccode
, Table4.Cdescription
FROM dbo.Table1
JOIN dbo.Table2 ON Table2.Acode = Table1.Acode
JOIN dbo.Table3 ON Table3.Bcode = Table1.Bcode
JOIN dbo.Table4 ON Table4.Ccode = Table1.Ccode;
Thanks for help
LEFT Join worked well. I tried to narrow down the tables one by one and found the table where I was getting duplicate records. After finding table I found that I forgot to add Unique key and 1 record (Description) was entered twice which was giving duplicate records and total number of rows were increased.
Thanks all to help me out,and Dan Guzman to point me for duplicate codes.

Getting Sum of MasterTable's amount which joins to DetailTable

I have two tables:
1. Master
| ID | Name | Amount |
|-----|--------|--------|
| 1 | a | 5000 |
| 2 | b | 10000 |
| 3 | c | 5000 |
| 4 | d | 8000 |
2. Detail
| ID |MasterID| PID | Qty |
|-----|--------|-------|------|
| 1 | 1 | 1 | 10 |
| 2 | 1 | 2 | 20 |
| 3 | 2 | 2 | 60 |
| 4 | 2 | 3 | 10 |
| 5 | 3 | 4 | 100 |
| 6 | 4 | 1 | 20 |
| 7 | 4 | 3 | 40 |
I want to select sum(Amount) from Master which joins to Deatil where Detail.PID in (1,2,3)
So I execute the following query:
SELECT SUM(Amount) FROM Master M INNER JOIN Detail D ON M.ID = D.MasterID WHERE D.PID IN (1,2,3)
Result should be 20000. But I am getting 40000
See this fiddle. Any suggestion?
You are getting exactly double the amount because the detail table has two occurences for each of the PIDs in the WHERE clause.
See demo
Use
SELECT SUM(Amount)
FROM Master M
WHERE M.ID IN (
SELECT DISTINCT MasterID
FROM DETAIL
WHERE PID IN (1,2,3) )
What is the requirement of joining the master table with details when you have all your columns are in Master table.
Also, isnt there any FK relationhsip defined on these tables. Looking at your data it seems to me that there should be FK on detail table for MasterId. If that is the case then you do not need join the table at all.
Also, in case you want to make sure that you have records in details table for the records for which you need sum and there is no FK relationship. Then you could give a try for exists instead of join.