I have a table 2 transactions let's say table A and B, for some cases i need to transfer row datas from table B to A as new table with several conditions :
The price for the data transferred will follow from the previous data
The same date will not processed into results
When there is no previous data, it will not processed into results
For Example :
-----------Table A------------- ----------Table B----------
product | Date | Price | | Product | Date |
A | 2019-01-01 | 10 | | A | 2018-11-05 |
A | 2019-01-15 | 15 | | A | 2019-01-10 |
A | 2019-01-25 | 20 | | A | 2019-01-12 |
A | 2019-05-01 | 25 | | A | 2019-01-27 |
A | 2019-07-02 | 30 | | B | 2019-02-10 |
B | 2019-02-05 | 40 | | B | 2019-04-22 |
B | 2019-04-22 | 50 | | B | 2019-05-13 |
B | 2019-05-12 | 40 |
Result :
-----------Table C-------------
product | Date | Price |
A | 2019-01-01 | 10 |
A | 2019-01-10 | 10 | *The prices follow the data in the previous date (2019-01-01)
A | 2019-01-12 | 10 | *The prices follow the data in the previous date (2019-01-01)
A | 2019-01-15 | 15 |
A | 2019-01-25 | 20 |
A | 2019-01-27 | 20 | *The prices follow the data in the previous date (2019-01-25)
A | 2019-05-01 | 25 |
A | 2019-07-02 | 30 |
B | 2019-02-05 | 40 |
B | 2019-02-10 | 40 | *The prices follow the data in the previous date (2019-02-05)
B | 2019-04-22 | 50 |
B | 2019-05-12 | 40 |
B | 2019-05-13 | 40 | *The prices follow the data in the previous date (2019-05-12)
NOTE:
For product A in Table B on 2018-11-05 not processed into results because there's no data before that date in the table A for that product.
For product B in Table B on 2019-04-22 not processed into results because the date and product in table A and B are the same (The data is already in table A)
I try not to use looping mechanism because my data reaches millions, but i was too dizzy to think about it.
One way is using group by in a cte and then union:
WITH cte AS(
SELECT b.product,
b.[Date],
MAX(a.[Date]) AS [DateValue]
FROM TableA AS a
INNER JOIN TableB AS b ON a.product = b.product
WHERE a.[Date] <= b.[Date]
GROUP BY b.product, b.[Date]
)
SELECT *
FROM dbo.TableA AS a
UNION
SELECT b.product,
b.[Date],
a.Price
FROM cte AS c
INNER JOIN dbo.TableB AS b ON b.product = c.product AND b.[Date] = c.[Date]
INNER JOIN dbo.TableA AS a ON a.product = c.product AND a.[Date] = c.[DateValue]
ORDER BY product, [Date]
One method uses union all and cross apply:
select ab.product, ab.date, p.price
from ((select a.product, a.date
from a
) union -- intentional to remove duplicates
(select b.product b.date
from b
)
) ab cross apply
(select top (1) a.price
from a
where a.product = ab.product and a.date <= ab.date
order by ab.date desc
) p;
Note that cross apply will eliminate the rows from b that have no price.
If SQL support the ignore nulls option on either last_value() or lag(), this would be more appropriate with a full join:
select coalesce(a.product, b.product) as product,
coalesce(a.date, b.date) as date,
coalesce(a.price,
lag(ignore nulls a.price) over (partition by coalesce(a.product, b.product) order by coalesce(a.date, b.date)) as price
from a full join
b
on a.product = b.product and a.date = b.date;
Alas, SQL Server does not (currently) support that. You can make that work with a bit of effort and additional subqueries.
SQL MERGE is a very powerful tool to perform "CRUD" operation based on some condition...
Please follow the link for more details of this feature.
http://www.sqlservertutorial.net/sql-server-basics/sql-server-merge/
https://www.essentialsql.com/introduction-merge-statement/
Please feel free to ask if you have any doubt.
Related
[Simplfying my tables] I have an excel model that outputs a forecast based on clients orders aggregated by month.
Table A
+----------+--------+----------+
| Customer | Volume | Date |
+----------+--------+----------+
| A | 100 | 1/1/2020 |
| B | 100 | 1/1/2020 |
| C | 100 | 1/1/2020 |
| A | 100 | 2/1/2020 |
| B | 100 | 2/1/2020 |
| C | 100 | 2/1/2020 |
+----------+--------+----------+
I want to join this data to live data coming from a database that is aggregated monthly by first date as well (i.e. if customer orders on 1/5/20 = 1/1/2020). Table B:
+----------+--------+----------+
| Customer | Volume | Date |
+----------+--------+----------+
| A | 100 | 1/1/2020 |
| A | 100 | 1/1/2020 |
| A | 100 | 1/1/2020 |
| B | 100 | 2/1/2020 |
| B | 100 | 2/1/2020 |
| Z | 10 | 2/1/2020 |
+----------+--------+----------+
I also have a third table that only has the Customer's first order date: Table C:
+----------+----------+--+
| Customer | Date | |
+----------+----------+--+
| A | 1/1/2020 | |
| B | 1/1/2020 | |
| C | 1/1/2020 | |
| Z | 2/1/2020 | |
+----------+----------+--+
I want to compare how the forecast (A) is tracking against the live data coming in (B), as well as add in the Customer's first Order Date (C). Since (B) is the most granular data, I am starting with this as my base. If I do a left join to (A) and (C) then some of Table A gets cut off (which I do not want); however my Table (C) data comes in correctly. If I do a full outer join to (A) then I do get the total forecast coming in correctly but the full outer join messes up Table (C). To add more complexity, Table B might have additional customers that were not part of the forecast so I need to see this data as well.
Forecast Number cut off:
select
b.customer,
b.volume,
b.date,
a.volume,
c.date
from b
left join a on b.customer = a.customer
left join c on c.customer = b.customer
Incorrect Data:
select
b.customer,
b.volume,
b.date,
a.volume,
c.date
from b
full outer join a on b.customer = a.customer
left join c on c.customer = b.customer
Use the coalesce function to join Table C with entries of both tables A and B:
select
coalesce(a.customer, b.customer),
b.volume,
b.date,
a.volume,
c.date
from b
full outer join a on b.customer = a.customer
left join c on c.customer = COALESCE(b.customer, a.customer)
TelNo | OrderDate | Orders
A | 2017-01-01 | 5
A | 2017-02-02 | 4
A | 2017-07-05 | 6
A | 2017-09-10 | 10
B | 2017-03-01 | 3
B | 2017-04-12 | 6
B | 2017-11-10 | 4
Above is the order table, requirement is to find the sum of 'Orders' for each 'TelNo' within last 6 months from the 'OrderDate' against each record of the table. Below is the expected output;
TelNo | OrderDate | Sum_of_orders
A | 2017-01-01 | 5
A | 2017-02-02 | 9
A | 2017-07-05 | 10
A | 2017-09-10 | 16
B | 2017-03-01 | 3
B | 2017-04-12 | 9
B | 2017-11-10 | 4
I've tried different combinations of CTE and sum(case -- ) over (partition by --) approaches(sql-server-2016), but didn't arrive at a solution. Appreciate if someone can help out in this.
You can use a query like below to get your desired results
See working demo
select t1.TelNo, t1.OrderDate, Sum_of_orders =sum(t2.Orders)
from t t1
join t t2
on t1.TelNo=t2.Telno
and t2.OrderDate between DATEADD(m,-6,t1.OrderDate) and t1.OrderDate
group by t1.TelNo, t1.OrderDate
I would use apply :
select t.TelNo, t.OrderDate, tt.Sum_of_orders
from table t cross apply (
select sum(t1.orders) Sum_of_orders
from table t1
where t1.TelNo = t.TelNo and
t1.OrderDate >= dateadd(mm, -6, t.orderdate) and
t1.OrderDate <= t.OrderDate
) tt;
You can use below query to get desired results:
select mt.TelNo, mt.OrderDate, sum(mt1.orders) from MyTbl mt
left join MyTbl mt1 on mt.TelNo = mt1.TelNo and datediff(day,mt1.OrderDate, mt.OrderDate) <= 180
and mt1.orderdate <= mt.OrderDate
Group by mt.TelNo, mt.OrderDate
order by 1,2
i need some help.
I have two tables like this.
Table Person
p_id | name | registration date
-----------------------------
1 | ABC | 2018-01-01
2 | DEF | 2018-02-02
3 | GHI | 2018-03-01
4 | JKL | 2018-01-02
5 | MNO | 2018-02-01
6 | PQR | 2018-03-02
Table Order
Order_id| p_id | order_date
----------------------------
123 | 1 | 2018-01-05
345 | 2 | 2018-02-06
678 | 3 | 2018-03-07
910 | 4 | 2018-01-08
012 | 3 | 2018-03-04
234 | 4 | 2018-01-05
567 | 5 | 2018-02-08
890 | 6 | 2018-03-09
I need to find out how many days is the longest period when this two table aren't updated.
What's the easiest query to get the result in SQL?
Thank you
UPDATE:
The result should be showing the longest date gap between order_date and registration_date. Because the longest date gap is 2018-01-08 and 2018-02-01, so the result should return '24'
Try this:
SELECT MAX(DATE_PART('day', now() - '2018-02-15'::TIMESTAMP)) FROM person p
JOIN order o
USING (p_id)
Assuming current PostgreSQL and lots of orders per person on avg., this should be among the fastest options:
SELECT o.order_date - p.registration_date AS days
FROM person p
CROSS JOIN LATERAL (
SELECT order_date
FROM "order" -- order is a reserved word!
WHRE p_id = p.p_id
ORDER BY 1 DESC -- assuming NOT NULL
LIMIT 1
) o
ORDER BY 1 DESC
LIMIT 1;
Needs an index on "orders"(p_id, order_date).
Detailed explanation:
Optimize GROUP BY query to retrieve latest record per user
Select first row in each GROUP BY group?
You seem to want:
select max(o.order_date - p.registration_date)
from person p join
orders o
on p.p_id = o.p_id;
select max((date_part('day',age(order_date, "registration date")))) + 1 as dif
from (
select "p_id" ,max(order_date) order_date
from "Order"
group by "p_id"
) T1
left join Person T2 on T1.p_id = T2.p_id
| maxday |
|--------|
| 8 |
[SQL Fiddle DEMO LINK]
I'm trying to group sales data based on a sellers' name. The name is available in another table. My tables look like this:
InvoiceRow:
+-----------+----------+-----+----------+
| InvoiceNr | Title | Row | Amount |
+-----------+----------+-----+----------+
| 1 | Chair | 1 | 2000.00 |
| 2 | Sofa | 1 | 1500.00 |
| 2 | Cushion | 2 | 2000.00 |
| 3 | Lamp | 1 | 6500.00 |
| 4 | Table | 1 | -500.00 |
+-----------+----------+-----+----------+
InvoiceHead:
+-----------+----------+------------+
| InvoiceNr | Seller | Date |
+-----------+----------+------------+
| 1 | Adam | 2016-01-01 |
| 2 | Lisa | 2016-01-04 |
| 3 | Adam | 2016-01-08 |
| 4 | Carl | 2016-01-17 |
+-----------+----------+------------+
The query that I'm working with currently looks like this:
SELECT SUM(Amount)
FROM InvoiceRow
WHERE InvoiceNr IN (
SELECT InvoiceNr
FROM InvoiceHead
WHERE Date >= '2016-01-01' AND Date < '2016-02-01'
)
This works and will sum the values of all rows of all invoices (total sales) in the month of january.
What I want to do is a sales summary grouped by each sellers' name. Something like this:
+----------+------------+
| Seller | Amount |
+----------+------------+
| Adam | 8500.00 |
| Lisa | 3500.00 |
| Carl | -500.00 |
+----------+------------+
And after that maybe even grouped by month (but that's not part of this question, I'm hoping to be able to figured that out if I solve this).
I've tried all kinds of joins but I end up with a lot of duplicates, and I'm not sure how to SUM and group at the same time. Does anyone know how to do this?
Try This
SELECT seller, SUM(amount) FROM InvoiceRow
JOIN InvoiceHead
ON InvoiceRow.InvoiceNr = InvoiceHead.InvoiceNr
GROUP BY InvoiceHead.seller;
OR If you want to between two date. Try This
SELECT seller, SUM(amount) FROM InvoiceRow
JOIN InvoiceHead
ON InvoiceRow.InvoiceNr = InvoiceHead.InvoiceNr
WHERE InvoiceHead.Date >= '2016-01-01' AND InvoiceHead.Date < '2016-02-01'
GROUP BY InvoiceHead.seller;
You just need to join the tables, filter result by date as you need and then make grouping:
select
H.Seller,
sum(R.Amount) as Amount
from InvoiceHead as H
left outer join InvoiceRow as R on R.InvoiceNr = H.InvoiceNr
where H. Date >= '2016-01-01' AND H.Date < '2016-02-01'
group by H.Seller
SELECT t.seller,sum(s.amount)
FROM invoiceRow s join InvoiceHead t
ON s.invoiceNr = t.invoiceNr
group by t.seller
You should just sum them up. If date range is necessary, you can add a where clause after the ON clause and filter you dates like this:
SELECT t.seller,sum(s.amount)
FROM invoiceRow s join InvoiceHead t
ON s.invoiceNr = t.invoiceNr
WHERE t.date between '01-01-2016' and '31-01-2016'
group by t.seller
You may try this once:
SELECT ih.Seller,
(
SELECT SUM(Amount) FROM invoicerow ir
INNER JOIN invoicehead ih1
ON (ir.InvoiceNr = ih1.InvoiceNr)
WHERE ih1.Seller = ih.Seller
) AS Amount
FROM invoicehead ih
GROUP BY ih.Seller
I am trying to pull some data with transaction counts, by branch, by week, which will later be used to feed some dynamic .Net charts.
I have a calendar table, I have a branch table and I have a transaction table.
Here is my DB info (only relevant columns included):
Branch Table:
ID (int), Branch (varchar)
Calendar Table:
Date (datetime), WeekOfYear(int)
Transaction Table:
Date (datetime), Branch (int), TransactionCount(int)
So, I want to do something like the following:
Select b.Branch, c.WeekOfYear, sum(TransactionCount)
FROM BranchTable b
LEFT OUTER JOIN TransactionTable t
on t.Branch = b.ID
JOIN Calendar c
on t.Date = c.Date
WHERE YEAR(c.Date) = #Year // (SP accepts this parameter)
GROUP BY b.Branch, c.WeekOfYear
Now, this works EXCEPT when a branch doesn't have any transactions for a week, in which case NO RECORD is returned for that branch on that week. What I WANT is to get that branch, that week and "0" for the sum. I tried isnull(sum(TransactionCount), 0) - but that didn't work, either. So I will get the following (making up sums for illustration purposes):
+--------+------------+-----+
| Branch | WeekOfYear | Sum |
+--------+------------+-----+
| 1 | 1 | 25 |
| 2 | 1 | 37 |
| 3 | 1 | 19 |
| 4 | 1 | 0 | //THIS RECORD DOES NOT GET RETURNED, BUT I NEED IT!
| 1 | 2 | 64 |
| 2 | 2 | 34 |
| 3 | 2 | 53 |
| 4 | 2 | 11 |
+--------+------------+-----+
So, why doesn't the left-outer join work? Isn't that supposed to
Any help will be greatly appreciated. Thank you!
EDIT: SAMPLE TABLE DATA:
Branch Table:
+----+---------------+
| ID | Branch |
+----+---------------+
| 1 | First Branch |
| 2 | Second Branch |
| 3 | Third Branch |
| 4 | Fourth Branch |
+----+---------------+
Calendar Table:
+------------+------------+
| Date | WeekOfYear |
+------------+------------+
| 01/01/2015 | 1 |
| 01/02/2015 | 1 |
+------------+------------+
Transaction Table
+------------+--------+--------------+
| Date | Branch | Transactions |
+------------+--------+--------------+
| 01/01/2015 | 1 | 12 |
| 01/01/2015 | 1 | 9 |
| 01/01/2015 | 2 | 4 |
| 01/01/2015 | 2 | 2 |
| 01/01/2015 | 2 | 23 |
| 01/01/2015 | 3 | 42 |
| 01/01/2015 | 3 | 19 |
| 01/01/2015 | 3 | 7 |
+------------+--------+--------------+
If you want to return a query that contains each Branch and each week, then you'll need to first create a full list of that, then use a LEFT JOIN to the transactions to get the count. The code will be similar to:
select bc.Branch,
bc.WeekOfYear,
TotalTransaction = coalesce(sum(t.TransactionCount), 0)
from
(
select b.id, b.branch, c.WeekOfYear, c.date
from branch b
cross join Calendar c
-- if you want to limit the number of rows returned use a WHERE to limit the weeks
-- so far in the year or using the date column
WHERE c.date <= getdate()
and YEAR(c.Date) = #Year // (SP accepts this parameter)
) bc
left join TransactionTable t
on t.Date = bc.Date
and bc.id = t.branch
GROUP BY bc.Branch, bc.WeekOfYear
See Demo
This code will create in your subquery a full list of each branch with each date. Once you have this list, then you can JOIN to the transactions to get your total transaction count and you'd return each date as you want.
Bring in the Calendar before you bring in the transactions:
SELECT b.Branch, c.WeekOfYear, sum(TransactionCount)
FROM BranchTable b
INNER JOIN CalendarTable c ON YEAR(c.Date) = #Year
LEFT JOIN TransactionTable t ON t.Branch = b.ID AND t.Date = c.Date
GROUP BY b.Branch, c.WeekOfYear
ORDER BY c.WeekOfYear, b.Branch