How to insert a Number value which is a difference between field 1 and field 2 of another table in Oracle? - sql

I have a table name ITEM that consist of
+-------+-----------+--------------+
| Item | PrevValue | CurrentValue |
+-------+-----------+--------------+
| ItemA | 2 | 10 |
| ItemB | 1 | 2 |
+-------+-----------+--------------+
And another table name PAYMENT that will require insert.
INSERT INTO PAYMENT(ID, Billing_Date, Due_Date, Value_Amount)
VALUES (1,TO_DATE('23-JULY-2020','DD-MON-YYYY'), TO_DATE('21-AUGUST-2020','DD-MON-YYYY'),
**CurValue - PrevValue** );
How do i correctly calculate the differences between PrevValue and CurValue in ITEM and insert them into PAYMENT?

The query will be, simply INSERT....SELECT:
INSERT INTO PAYMENT(ID, Billing_Date, Due_Date, Value_Amount)
select 1,TO_DATE('23-JULY-2020','DD-MON-YYYY'), TO_DATE('21-AUGUST-2020','DD-MON-YYYY'), (CurValue - PrevValue) from ITEM where Item = '<Item_Name>';

Related

postgres insert data from an other table inside array type columns

I have tow table on Postgres 11 like so, with some ARRAY types columns.
CREATE TABLE test (
id INT UNIQUE,
category TEXT NOT NULL,
quantitie NUMERIC,
quantities INT[],
dates INT[]
);
INSERT INTO test (id, category, quantitie, quantities, dates) VALUES (1, 'cat1', 33, ARRAY[66], ARRAY[123678]);
INSERT INTO test (id, category, quantitie, quantities, dates) VALUES (2, 'cat2', 99, ARRAY[22], ARRAY[879889]);
CREATE TABLE test2 (
idweb INT UNIQUE,
quantities INT[],
dates INT[]
);
INSERT INTO test2 (idweb, quantities, dates) VALUES (1, ARRAY[34], ARRAY[8776]);
INSERT INTO test2 (idweb, quantities, dates) VALUES (3, ARRAY[67], ARRAY[5443]);
I'm trying to update data from table test2 to table test only on rows with same id. inside ARRAY of table test and keeping originals values.
I use INSERT on conflict,
how to update only 2 columns quantities and dates.
running the sql under i've got also an error that i don't understand the origin.
Schema Error: error: column "quantitie" is of type numeric but expression is of type integer[]
INSERT INTO test (SELECT * FROM test2 WHERE idweb IN (SELECT id FROM test))
ON CONFLICT (id)
DO UPDATE
SET
quantities = array_cat(EXCLUDED.quantities, test.quantities),
dates = array_cat(EXCLUDED.dates, test.dates);
https://www.db-fiddle.com/f/rs8BpjDUCciyZVwu5efNJE/0
is there a better way to update table test from table test2, or where i'm missing the sql?
update to show result needed on table test:
**Schema (PostgreSQL v11)**
| id | quantitie | quantities | dates | category |
| --- | --------- | ---------- | ----------- | --------- |
| 2 | 99 | 22 | 879889 | cat2 |
| 1 | 33 | 34,66 | 8776,123678 | cat1 |
Basically, your query fails because the structures of the tables do not match - so you cannot insert into test select * from test2.
You could work around this by adding "fake" columns to the select list, like so:
insert into test
select idweb, 'foo', 0, quantities, dates from test2 where idweb in (select id from test)
on conflict (id)
do update set
quantities = array_cat(excluded.quantities, test.quantities),
dates = array_cat(excluded.dates, test.dates);
But this looks much more convoluted than needed. Essentially, you want an update statement, so I would just recommend:
update test
set
dates = test2.dates || test.dates,
quantities = test2.quantities || test.quantities
from test2
where test.id = test2.idweb
Note that this ues || concatenation operator instead of array_cat() - it is shorter to write.
Demo on DB Fiddle:
id | category | quantitie | quantities | dates
-: | :------- | --------: | :--------- | :------------
2 | cat2 | 99 | {22} | {879889}
1 | cat1 | 33 | {34,66} | {8776,123678}

How to update a table cells from another table's columns with different conditions?

Let assume that I have two tables in my database as below:
Table 1 (current_prices): Which contains some stuffs and their prices and it updates one time per day:
# current_prices
| commodity | price |
____________________
| stuff1 | price1
| stuff2 | price2
| stuff3 | price3
|. |
|. |
|. |
| stuffN | priceN
Table 2 (stat_history): Which divide stuffs in price ranges and keep the number of elements of each range for all days as below:
# stat_history
| date | range1_count | range2_count | range3_count
________________________________________________________
| 20200411 | 12 | 5 | 9
| 20200412 | 10 | 5 | 11
| 20200413 | 13 | 4 | 9
| 20200414 | 15 | 3 | 8
The content of stat_history table are generated from current_price contents at the end of the day.
Currently I use multiple Update-Insert (Upsert) queries to update my stat_history table as below:
insert into stat_history (date, range1_count)
select now()::date , count(stuff) as range1_count from current_prices
where 0 < price and price < VAL1
on conflict(day)
update set
range1_count = excluded.range1_count
insert into stat_history (date, range2_count)
select now()::date , count(stuff) as range2_count from current_prices
where VAL1 < price and price < VAL2
on conflict(day)
update set
range2_count = excluded.range2_count
..... (blah blah)
The question is:
Is there any shorter, simpler or more efficient way to do this (In a single SQL query for example)?
You could do conditional counts, using Postgres standard filter clause:
insert into stat_history (date, range1_count)
select
now()::date,
count(stuff) filter(where price >= 0 and price < VAL1) as range1_count,
count(stuff) filter(where price >= VAL1 and price < VAL2) as range2_count
from current_prices
where price >= 0 and price < VAL2
on conflict(day)
update set
range1_count = excluded.range1_count
range2_count = excluded.range2_count
Notes:
I adapted the logic that puts rows in the intervals to make them contiguous (in your original query for example, a price that is equal to VA1 would never be counted in)
with this logic at hand, you might not even need the on conflict clause

SQL: Update max values with min values in same table

I have a table with a priority. Something like that:
id priority name
-------------------------------
1 5 SomeFunnyName
2 10 SomeFunnyName1
3 20 SomeFunnyName2
4 30 SomeFunnyName3
5 40 SomeFunnyName4
Data with higher priority was proceeded faster. But now i have to change the priority logic. So data with lower priority will proceed faster.
How can i update this table that the data with the highest priority will now have the lowest priority?
When you multiply by minus one it would change the priority, this way you can revert back easily by again multiplying by minus one
UPDATE TABLE SET PRIORITY=-1*PRIORITY
You can try to use MAX and MIN get priority and some calculation to make it change the MAX and MIN priority from the table.
CREATE TABLE T(
id int,
priority int,
name varchar(50)
);
insert into t values (1,5,'SomeFunnyName');
insert into t values (2,10,'SomeFunnyName1');
insert into t values (3,20,'SomeFunnyName2');
insert into t values (4,30,'SomeFunnyName3');
insert into t values (5,40,'SomeFunnyName4');
UPDATE T
Set priority = maxVal - priority + minVal
FROM (
SELECT MAX(priority) maxVal,MIN(priority) minVal
FROM T
) t1
Query 1:
SELECT * FROM T
Results:
| id | priority | name |
|----|----------|----------------|
| 1 | 40 | SomeFunnyName |
| 2 | 35 | SomeFunnyName1 |
| 3 | 25 | SomeFunnyName2 |
| 4 | 15 | SomeFunnyName3 |
| 5 | 5 | SomeFunnyName4 |

Select rows with same value in one column but different value in another column

I've been trying to build this query but am new to SQL so I'd really appreciate some help.
In the below table example, I have a Customer Code, a linked Customer Code (which is used to link a child customer to a parent customer), a salesperson, and other irrelevant columns. The goal is to have one Salesperson for each parent customer and it's children. So in the example, CustCode #100 is the parent of itself, #200, #500, and #800. All of these accounts have the same Salesperson (JASON) which is perfect. But for CustCode #300, it is the parent of itself, #400, and #600. However, there isn't one salesperson assigned - its both JIM and SUZY. I want to build a query that shows all accounts for this example. Basically, accounts where the Salesperson field isn't the same value for all of it's child customers.
I tried a Where clause for Salesperson <> Salesperson but its not showing up right.
+-----------+-----------------+------------+----------------------+
| CustCode | Linked CustCode | Salesperson| additional columns...|
+-----------+-----------------+------------+----------------------+
| 100 | 100 | JASON | ... |
| 200 | 100 | JASON | ... |
| 300 | 300 | JIM | ... |
| 400 | 300 | JIM | ... |
| 500 | 100 | JASON | ... |
| 600 | 300 | SUZY | ... |
| 700 | NULL | JIM | ... |
| 800 | 100 | JASON | ... |
+-----------+-----------------+------------+----------------------+
Thanks so much for your help!
You can do self join on the table.
select distinct r2.* from
table r1
join table r2
on
r1.linkedcustcode = r2.linkedcustcode and r1.salesperson <> r2.salesperson
This solution uses a recursive CTE first to build the hierarchy and find the leading code for each row, even if a linked code points to a row which is pointing to an upper row itself.
The final query shows the count of different Salespersons:
DECLARE #tbl TABLE(CustCode INT,[Linked CustCode] INT,Salesperson VARCHAR(100));
INSERT INTO #tbl VALUES
(100,100,'JASON')
,(200,100,'JASON')
,(300,300,'JIM')
,(400,300,'JIM')
,(500,100,'JASON')
,(600,300,'SUZY')
,(700,NULL,'JIM')
,(800,100,'JASON');
--The query
WITH CleanUp AS
(
SELECT CustCode
,CASE WHEN [Linked CustCode]=CustCode THEN NULL ELSE [Linked CustCode] END AS [Linked CustCode]
,Salesperson
FROM #tbl
)
,recCTE AS
(
SELECT CustCode AS LeadingCode,CustCode,[Linked CustCode],Salesperson
FROM CleanUp
WHERE [Linked CustCode] IS NULL
UNION ALL
SELECT recCTE.LeadingCode,t.CustCode,t.[Linked CustCode],t.Salesperson
FROM recCTE
INNER JOIN CleanUp AS t ON t.[Linked CustCode]=recCTE.CustCode
)
SELECT LeadingCode,COUNT(DISTINCT Salesperson) AS CountSalesperson
FROM recCTE
GROUP BY LeadingCode
The result
LeadingCode CountSalesperson
100 1
300 2
700 1

How to show integer value column to be string value in display using SQL

My sale table
ID Sales Amount
--------------------
101 1 1000
102 1 1500
103 2 2000
104 3 2500
In the above table Sales column 1 refer to 'keyboard' 2 refer to 'Mouse' and 3 refer to 'CD'.
If i use SELECT * FROM Sale WHERE ID=103
it will return
ID Sales Amount
------------------
103 2 2000
but I need to display like below
ID Sales Amount
------------------
103 Mouse 2000
In db i need to store sales value as int like '1,2,3,4,5' but when show to user i need to display a unique string value for each integer value.
SELECT
ID,
CASE Sales
When 1 Then 'KeyBoard'
When 2 Then 'Mouse'
When 3 Then 'CD'
END AS Sales,
Amount
FROM
Sale
WHERE
Id = 103
I suggest you to create a table like this:
[Table: SaleType]
+----+----------+
| Id | Name |
+----+----------+
| 1 | Keyboard |
| 2 | Mouse |
| 3 | CD |
: .. : ... :
+----+----------+
And set the Sales column in Sale tables a Foreign Key(FK) of SaleType, then you can have your result by using this query:
SELECT
Sale.ID,
SaleType.Name,
Sale.Amount
FROM
Sale
JOIN
SaleType ON Sale.Sales = SaleType.Id