SQL Server: subtract or sum between rows in the same column then update the results - sql

I have a table my MS SQL Server, which has a standard row type BID. I want to subtract all the row type ASK from BID in column availableAmount then update the result into the BID row at the same column. At the same time, I want to calculate the sum of fulfilledAmount of row type ASK then update the result into the same column of row type BID. I'm still learning SQL but is it possible to do this complicate process?
EDIT
Example:
Before execution:
id | type | availableAmount | fulfilledAmount |
-----+------+-----------------+-----------------+
abcv | ASK | 500 | 500 |
xyzs | ASK | 600 | 600 |
scwd | BID | 10000 | 0 |
cd21 | ASK | 1300 | 1300 |
sadc | ASK | 3400 | 3400 |
2w3e | ASK | 2500 | 2500 |
After execution:
id | type | availableAmount | fulfilledAmount |
-----+------+-----------------+-----------------+
abcv | ASK | 500 | 500 |
xyzs | ASK | 600 | 600 |
scwd | BID | 1700 | 8300 |
cd21 | ASK | 1300 | 1300 |
sadc | ASK | 3400 | 3400 |
2w3e | ASK | 2500 | 2500 |

If I understood correct, you need something in the line of:
UPDATE myTable
SET availableAmount = availableAmount - (
SELECT SUM(availableAmount)
FROM myTable
WHERE TYPE = 'ASK'
)
,fulfilledAmount = (
SELECT SUM(fulfilledAmount)
FROM myTable
WHERE TYPE = 'ASK'
)
WHERE TYPE = 'BID'
AND ID ='scwd'

Related

postgres grouping

I am having a db names products where i wanted to select the price of each product based on the id, but the price that i stored in the table is from different sources. So i want one latest price from each of the source.
My table looks like this
id | name | source | updated_at | price
1 | ace | vanil | ... | 100
2 | vax | vanil | ... | 101
3 | tax | sunyil | ... | 200
1 | ace | sunyil | latest | 99.5
2 | vax | sunyil | latest | 100.5
3 | tax | vanil | latest | 199.5
3 | tax | vanil | ... | 220
3 | tax | vanil | ... | 211
3 | tax | vanil | ... | 205
3 | tax | sunyil | ... | 211
3 | tax | vanil | ... | 220
3 | tax | sunyil |latest_time | 220
1 | ace | sunyil | ... | 101
i want the output to be like this when my where condition is for id=3
id | name | source | updated_at | price
3 | tax | vanil | latest time| 199.5
3 | tax | sunyil | latest time| 220
i tried running the
select * from products WHERE id= '3' ORDER BY updated_at DESC LIMIT 1
but this one brings only one row irrespective of the source
could any one help me out with this. I am extremely new to postgres and sql queries. I would really appreciate your help.
It's not really clear what you want to do. If you would like to sum the price for the product with id 3 not having the text "..." in the column "updated_at", you can do this query:
SELECT id, name, source, updated_at, SUM(price) FROM products
WHERE id = 3 and updated_at != '...'
GROUP BY id, name, source, updated_at ORDER BY updated_at;
See this example and try out: db<>fiddle
Modify the query to your desires if necessary.
Using DISTINCT ON:
SELECT DISTINCT ON (id, source) *
FROM products
WHERE id = 3
ORDER BY id, source, updated_at DESC;

SQL group column where other column is equal

I'm trying to select some information from a database.
I get a database with columns like:
Ident,Name,Length,Width,Quantity,Planned
Table data is as follow
+-----------+-----------+---------+---------+------------+---------+
| Ident | Name | Length | Width | Quantity | Planned |
+-----------+-----------+---------+---------+------------+---------+
| 12345 | Name1 | 1500 | 1000 | 20 | 5 |
| 23456 | Name1 | 1500 | 1000 | 30 | 13 |
| 34567 | Name1 | 2500 | 1000 | 10 | 2 |
| 45678 | Name1 | 2500 | 1000 | 10 | 4 |
| 56789 | Name1 | 1500 | 1200 | 20 | 3 |
+-----------+-----------+---------+---------+------------+---------+
my desired result, would be to group rows where "Name,Length and Width" are equal, sum the "Quantity" and reduce it by the sum of "Planned"
e.g:
- Name1,1500,1000,32 --- (32 because (20+30)-(5+13))
- Name1,2500,1000,14 --- (14 because (10+10)-(2+4)))
- Name1,1500,1200,17
now I got problems how to group or join these information to get the wished select. may be some you of can help me.. if further information's required, please write it in comment.
You can achieve it by grouping your table and subtract sums of Quantity and Planned.
select
Name
,Length
,Width
,sum(Quantity) - sum(Planned)
from yourTable
group by Name,Length,Width
select
A1.Name,A1.Length,A1.Width,((A1.Quantity + A2.Quantity) -(A1.Planned+A2.Planned))
from `Table` AS A1, `Table` AS A2
where A1.Name = A2.Name and A1.Length = A2.Length and A1.Width = A2.Width
group by (whatever)
So you are comparing these columns form the same table?

SQL: tricky question for finding lockout dates

Hope you can help. We have a table with two columns Customer_ID and Trip_Date. The customer receives 15% off on their first visit and on every visit where they haven't received the 15% off offer in the past thirty days. How do I write a single SQL query that finds all days where a customer received 15% off?
The table looks like this
+-----+-------+----------+
| Customer_ID | date |
+-----+-------+----------+
| 1 | 01-01-17 |
| 1 | 01-17-17 |
| 1 | 02-04-17 |
| 1 | 03-01-17 |
| 1 | 03-15-17 |
| 1 | 04-29-17 |
| 1 | 05-18-17 |
+-----+-------+----------+
The desired output would look like this:
+-----+-------+----------+--------+----------+
| Customer_ID | date | received_discount |
+-----+-------+----------+--------+----------+
| 1 | 01-01-17 | 1 |
| 1 | 01-17-17 | 0 |
| 1 | 02-04-17 | 1 |
| 1 | 03-01-17 | 0 |
| 1 | 03-15-17 | 1 |
| 1 | 04-29-17 | 1 |
| 1 | 05-18-17 | 0 |
+-----+-------+----------+--------+----------+
We are doing this work in Netezza. I can't think of a way using just window functions, only using recursion and looping. Is there some clever trick that I'm missing?
Thanks in advance,
GF
You didn't tell us what your backend is, nor you gave some sample data and expected output nor you gave a sensible data schema :( This is an example based on guess of schema using postgreSQL as backend (would be too messy as a comment):
(I think you have Customer_Id, Trip_Date and LocationId in trips table?)
select * from trips t1
where not exists (
select * from trips t2
where t1.Customer_id = t2.Customer_id and
t1.Trip_Date > t2.Trip_Date
and t1.Trip_date - t2.Trip_Date < 30
);

T-SQL return individual values instead of cumulative value

I have a 1 table in a db that stored Incoming, Outgoing and Net values for various Account Codes over time. Although there is a date field the sequence of events per Account Code is based on the "Version" number where 0 = original record for each Account Code and it increments by 1 after each change to that Account Code.
The Outgoing and Incoming values are stored in the db as cumulative values rather than the individual transaction value but I am looking for a way to Select * From this table and return the individual amounts as opposed to the cumulative.
Below are test scripts of table and data, and also 2 examples.
If i Select where code = '123' in the test table I currently get this (values are cumulative);
+------+------------+---------+---------+---------+-----+
| Code | Date | Version | Incoming| Outgoing| Net |
+------+------------+---------+---------+---------+-----+
| 123 | 01/01/2018 | 0 | 100 | 0 | 100 |
| 123 | 07/01/2018 | 1 | 150 | 0 | 150 |
| 123 | 09/01/2018 | 2 | 150 | 100 | 50 |
| 123 | 14/01/2018 | 3 | 200 | 100 | 100 |
| 123 | 18/01/2018 | 4 | 200 | 175 | 25 |
| 123 | 23/01/2018 | 5 | 225 | 175 | 50 |
| 123 | 30/01/2018 | 6 | 225 | 225 | 0 |
+------+------------+---------+---------+---------+-----+
This is what I would like to see (each individual transaction);
+------+------------+---------+----------+----------+------+
| Code | Date | Version | Incoming | Outgoing | Net |
+------+------------+---------+----------+----------+------+
| 123 | 01/01/2018 | 0 | 100 | 0 | 100 |
| 123 | 07/01/2018 | 1 | 50 | 0 | 50 |
| 123 | 09/01/2018 | 2 | 0 | 100 | -100 |
| 123 | 14/01/2018 | 3 | 50 | 0 | 50 |
| 123 | 18/01/2018 | 4 | 0 | 75 | -75 |
| 123 | 23/01/2018 | 5 | 25 | 0 | 25 |
| 123 | 30/01/2018 | 6 | 0 | 50 | -50 |
+------+------------+---------+----------+----------+------+
If I had the individual transaction values and wanted to report on the cumulative, I would use an OVER PARTITION BY, but is there an opposite to that?
I am not looking to redesign the create table or the process in which it is stored, I am just looking for a way to report on this from our MI environment.
Note: I've added other random Account Codes into this to emphasis how the data is not ordered by Code or Version, but by Date.
thanks in advance for any help.
USE [tempdb];
IF EXISTS ( SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Table1'
AND TABLE_SCHEMA = 'dbo')
DROP TABLE [dbo].[Table1];
GO
CREATE TABLE [dbo].[Table1]
(
[Code] CHAR(3)
,[Date] DATE
,[Version] CHAR(3)
,[Incoming] DECIMAL(20,2)
,[Outgoing] DECIMAL(20,2)
,[Net] DECIMAL(20,2)
);
GO
INSERT INTO [dbo].[Table1] VALUES
('123','2018-01-01','0','100','0','100'),
('456','2018-01-02','0','50','0','50'),
('789','2018-01-03','0','0','0','0'),
('456','2018-01-04','1','100','0','100'),
('456','2018-01-05','2','150','0','150'),
('789','2018-01-06','1','50','50','0'),
('123','2018-01-07','1','150','0','150'),
('456','2018-01-08','3','200','0','200'),
('123','2018-01-09','2','150','100','50'),
('789','2018-01-10','2','0','0','0'),
('456','2018-01-11','4','225','0','225'),
('789','2018-01-12','3','75','25','50'),
('987','2018-01-13','0','0','50','-50'),
('123','2018-01-14','3','200','100','100'),
('654','2018-01-15','0','100','0','100'),
('456','2018-01-16','5','250','0','250'),
('987','2018-01-17','1','50','50','0'),
('123','2018-01-18','4','200','175','25'),
('789','2018-01-19','4','100','25','75'),
('987','2018-01-20','2','150','125','25'),
('321','2018-01-21','0','100','0','100'),
('654','2018-01-22','1','0','0','0'),
('123','2018-01-23','5','225','175','50'),
('321','2018-01-24','1','100','50','50'),
('789','2018-01-25','5','100','50','50'),
('987','2018-01-26','3','150','150','0'),
('456','2018-01-27','6','250','250','0'),
('456','2018-01-28','7','270','250','20'),
('321','2018-01-29','2','100','100','0'),
('123','2018-01-30','6','225','225','0'),
('987','2018-01-31','4','175','150','25')
;
GO
SELECT *
FROM [dbo].[Table1]
WHERE [Code] = '123'
GO;
USE [tempdb];
IF EXISTS ( SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Table1'
AND TABLE_SCHEMA = 'dbo')
DROP TABLE [dbo].[Table1];
GO;
}
Just use lag():
select Evt, Date, Version,
(Loss - lag(Loss, 1, 0) over (partition by evt order by date)) as incoming,
(Rec - lag(Rec, 1, 0) over (partition by evt order by date)) as outgoing,
(Net - lag(Net, 1, 0) over (partition by evt order by date)) as net
from [dbo].[Table1];

Multiple self joins plus one inner join

I have two tables: ck_startup and ck_price. The price table contains the columns cu_type, prd_type, part_cd, qty, and dllrs. The startup table is linked to the price table through a one-to-many relationship on ck_startup.prd_type_cd = ck_price.prd_type.
The price table contains multiple entries for the same product/part/qty but under different customer types. Not all customer types have the same unique combination of those three values. I'm trying to create a query that will do two things:
Join some columns from ck_startup onto ck_price (description, and some additional values).
Join ck_price onto itself with a dllrs column for each customer type. So in total I would only have one instance of each unique key of product/part/qty, and a value in each customer's price column if they have one.
I've never worked with self joining tables, and so far I can only get records to show up where both customers have the same options available.
And because someone is going to demand I post sample code, here's the crappy query that doesn't show missing prices:
select pa.*, pac.dllrs from ck_price pa
join ck_price pac on pa.prd_type = pac.prd_type and pa.part_carbon_cd = pac.part_carbon_cd and pa.qty = pac.qty
where pa.cu_type = 'A' and pac.cu_type = 'AC';
EDIT: Here's sample data from the two tables, and how I want them to look when I'm done:
CK_STARTUP
+-----+-----------------+-------------+
| CD | DSC | PRD_TYPE_CD |
+-----+-----------------+-------------+
| 3D | Stuff | SKD3 |
| DC | Different stuff | SKD |
| DN2 | Similar stuff | SKD |
+-----+-----------------+-------------+
CK_PRICE
+---------+-------------+---------+-----+-------+
| CU_TYPE | PRD_TYPE_CD | PART_CD | QTY | DLLRS |
+---------+-------------+---------+-----+-------+
| A | SKD3 | 1 | 100 | 10 |
| A | SKD3 | 1 | 200 | 20 |
| A | SKD3 | 1 | 300 | 30 |
| A | SKD | 1 | 100 | 50 |
| A | SKD | 1 | 200 | 100 |
| AC | SKD3 | 1 | 300 | 30 |
| AC | SKD | 1 | 100 | 100 |
| AC | SKD | 1 | 200 | 200 |
| AC | SKD | 1 | 300 | 300 |
| AC | SKD | 1 | 400 | 400 |
+---------+-------------+---------+-----+-------+
COMBO:
+----+-----------------+---------+-----+---------+----------+
| CD | DSC | PART_CD | QTY | DLLRS_A | DLLRS_AC |
+----+-----------------+---------+-----+---------+----------+
| 3D | Stuff | 1 | 100 | 10 | null |
| 3D | Stuff | 1 | 200 | 20 | null |
| 3D | Stuff | 1 | 300 | 30 | 60 |
| DC | Different stuff | 1 | 100 | 50 | 100 |
| DC | Different stuff | 1 | 200 | 100 | 200 |
| DC | Different stuff | 1 | 300 | null | 300 |
| DC | Different stuff | 1 | 400 | null | 400 |
+----+-----------------+---------+-----+---------+----------+
Ok, take a look at below query and at the results:
SELECT *
FROM (SELECT
cs.cd, cs.dsc, cp.part_cd, cp.qty, cp.dllrs, cp.cu_type
FROM ck_startup cs
JOIN ck_price cp ON (cs.prd_type_cd = cp.prd_type_cd))
PIVOT (SUM(dllrs) AS dlllrs FOR (cu_type) IN ('A' AS a, 'AC' AS ac))
ORDER BY cd, qty
;
Output:
CD DSC PART_CD QTY A_DLLLRS AC_DLLLRS
-------- ----------------- ---------- ------- ---------- ----------
3D Stuff 1 100 10
3D Stuff 1 200 20
3D Stuff 1 300 30 30
DC Different stuff 1 100 50 50
DC Different stuff 1 200 100 100
DC Different stuff 1 300 150
DC Different stuff 1 400 200
DN2 Similar stuff 1 100 50 50
DN2 Similar stuff 1 200 100 100
DN2 Similar stuff 1 300 150
DN2 Similar stuff 1 400 200
It is not what you would expect, because I do not understand why you have different values in DLLRS_AC column that are in the CK_PRICE table? I mean, for example, why do you have 400 in last line of your output, not 200? Why is this value doubled (as others are in DLLRS_AC column)?
If you are using Oracle 10g, you can achieve the same result using DECODE and GROUP BY, take a look:
SELECT
cd,
dsc,
part_cd,
qty,
SUM(DECODE(cu_type, 'A', dllrs, NULL)) AS dllrs_a,
SUM(DECODE(cu_type, 'AC', dllrs, NULL)) AS dllrs_ac
FROM (
SELECT
cs.cd, cs.dsc, cp.part_cd, cp.qty, cp.dllrs, cp.cu_type
FROM ck_startup cs
JOIN ck_price cp ON (cs.prd_type_cd = cp.prd_type_cd)
)
GROUP BY cd, dsc, part_cd, qty
ORDER BY cd, qty;
Result is the same.
If you want to read more about pivoting, I recommend article by Tim Hall: Pivot and Unpivot at Oracle Base