I have a table ORDERS with a column named cache_total_price, spent by each client.
+----+-----------+------------+-----------+------------------+
| id | client_id | date | reference | cache_total_price|
+----+-----------+------------+-----------+------------------+
| 1 | 20 | 2019-01-01 | 004214 | 0 |
| 2 | 3 | 2019-01-03 | 007120 | 0 |
| 3 | 11 | 2019-01-04 | 002957 | 0 |
| 4 | 6 | 2019-01-07 | 003425 | 0 |
I have another table ORDERS_REFS where there is the price total spent for each orders id
+-----+-------------+------------+----------+---------------+------------+
| id | order_id | name | quantity | unit_price | total_price|
+-----+-------------+------------+----------+---------------+------------+
| 1 | 1 | Produit 19 | 3 | 49.57 | 148.71 |
| 2 | 1 | Produit 92 | 4 | 81.24 | 324.96 |
| 3 | 1 | Produit 68 | 2 | 17.48 | 34.96 |
| 4 | 2 | Produit 53 | 4 | 83.69 | 334.76 |
| 5 | 2 | Produit 78 | 6 | 5.99 | 35.94 |
I want to had to column cache_total_price the result of my query :
select sum(total_price) from orders_refs group by order_id;
result :
+--------------------+
| sum(total_price) |
+--------------------+
| 508.6299819946289 |
| 370.700008392334 |
| 132.3699951171875 |
| 2090.1800079345703 |
I've tried some queries with Insert into select or update set, but didn't worked :(
If you're wanting to update all the orders at once, in MySQL a subquery like this should do the trick. You could always add a WHERE clause to do one at a time.
UPDATE ORDERS
SET cache_total_price = (
SELECT sum(total_price) from ORDERS_REF where order_id = ORDERS.id
)
update t
set t.cache_total_price=x.sum_total_price
from ORDERS as t
join
(
select order_id,sum(total_price)as sum_total_price
from orders_refs group by order_id
)x on t.id=x.order_id
In SQL Server you can try this one.
I have a data orders that looks like this:
| Order | Step | Step Complete Date |
|:-----:|:----:|:------------------:|
| A | 1 | 11/1/2019 |
| | 2 | 11/1/2019 |
| | 3 | 11/1/2019 |
| | 4 | 11/3/2019 |
| | 5 | 11/3/2019 |
| | 6 | 11/5/2019 |
| | 7 | 11/5/2019 |
| B | 1 | 12/1/2019 |
| | 2 | 12/2/2019 |
| | 3 | |
| C | 1 | 10/21/2019 |
| | 2 | 10/23/2019 |
| | 3 | 10/25/2019 |
| | 4 | 10/25/2019 |
| | 5 | 10/25/2019 |
| | 6 | |
| | 7 | 10/27/2019 |
| | 8 | 10/28/2019 |
| | 9 | 10/29/2019 |
| | 10 | 10/30/2019 |
| D | 1 | 10/30/2019 |
| | 2 | 11/1/2019 |
| | 3 | 11/1/2019 |
| | 4 | 11/2/2019 |
| | 5 | 11/2/2019 |
What I need to accomplish is the following:
For each order, assign the 'Order_Completion_Date' field as the most recent 'Step_Complete_Date'. If ANY 'Step_Complete_Date' is NULL, then the value for 'Order_Completion_Date' should be NULL.
I set up a SQL FIDDLE with this data and my attempt, below:
SELECT
OrderNum,
MAX(Step_Complete_Date)
FROM
OrderNums
WHERE
Step_Complete_Date IS NOT NULL
GROUP BY
OrderNum
This is yielding:
ORDERNUM MAX(STEP_COMPLETE_DATE)
D 11/2/2019
A 11/5/2019
B 12/2/2019
C 10/30/2019
How can I achieve:
| OrderNum | Order_Completed_Date |
|:--------:|:--------------------:|
| A | 11/5/2019 |
| B | NULL |
| C | NULL |
| D | 11/2/2019 |
Aggregate function with KEEP can handle this
select ordernum,
max(step_complete_date)
keep (DENSE_RANK FIRST ORDER BY step_complete_date desc nulls first) res
FROM
OrderNums
GROUP BY
OrderNum
You can use a CASE expression to first count if there are any NULL values and if not then find the maximum value:
Query 1:
SELECT OrderNum,
CASE
WHEN COUNT( CASE WHEN Step_Complete_Date IS NULL THEN 1 END ) > 0
THEN NULL
ELSE MAX(Step_Complete_Date)
END AS Order_Completion_Date
FROM OrderNums
GROUP BY OrderNum
Results:
| ORDERNUM | ORDER_COMPLETION_DATE |
|----------|-----------------------|
| D | 11/2/2019 |
| A | 11/5/2019 |
| B | (null) |
| C | (null) |
First, you are representing dates as varchars in mm/dd/yyyy format (at least in fiddle). With max function it can produce incorrect result, try for example order with dates '11/10/2019' and '11/2/2019'.
Second, the most simple solution is IMHO to use fallback date for nulls and get null back when fallback date wins:
SELECT
OrderNum,
NULLIF(MAX(NVL(Step_Complete_Date,'~')),'~')
FROM
OrderNums
GROUP BY
OrderNum
(Example is still for varchars since tilde is greater than any digit. For dates, you could use 9999-12-31, for instance.)
I am attempting to find which "replenishment" (a positive transaction quantity) can be matched to a "requirement" (a negative transaction quantity).
The basic logic would be: For a given requirement, find the first available replenishment (whether that replenishment be from existing inventory, or from an upcoming change).
I am working with a table dbo_purchases_new that looks like this:
| Element_ID | Element | Transaction_Date | Transaction_Quantity | Total_Inventory |
|:----------:|:----------:|:----------------:|:--------------------:|:---------------:|
| | STOCK | | 5 | 5 |
| MO302 | Make_Order | 1/3/2019 | 1 | 6 |
| SO105 | Sale | 2/1/2019 | -1 | 5 |
| SO106 | Sale | 2/1/2019 | -1 | 4 |
| MO323 | Make_Order | 2/2/2019 | 1 | 5 |
| SO107 | Sale | 2/4/2019 | -1 | 4 |
| SO191 | Sale | 2/5/2019 | -1 | 3 |
| SO123 | Sale | 2/6/2019 | -1 | 2 |
| SO166 | Sale | 3/1/2019 | -1 | 1 |
| SO819 | Sale | 3/5/2019 | -1 | 0 |
| SO603 | Sale | 3/10/2019 | -4 | -3 |
| MO400 | Make_Order | 3/15/2019 | 1 | -2 |
| MO459 | Make_Order | 3/15/2019 | 1 | -1 |
| MO460 | Make_Order | 3/18/2019 | 1 | 0 |
| MO491 | Make_Order | 3/19/2019 | 1 | 1 |
| MO715 | Make_Order | 4/1/2019 | 3 | 4 |
| SO100 | Sale | 4/2/2019 | -1 | 3 |
| SO322 | Sale | 4/3/2019 | -1 | 2 |
| SO874 | Sale | 4/4/2019 | -1 | 1 |
| SO222 | Sale | 4/5/2019 | -1 | 0 |
| MO999 | Make_Order | 4/5/2019 | 1 | 1 |
| SO999 | Sale | 4/6/2019 | -1 | 0 |
that is being created as a result of this question.
I am now attempting to track which Make_Order will fulfill which Sale by tracking the Transaction_Quantity.
Ideally, the resulting dataset would look like this, where Replenishment and Replenishment_Date are newly added columns:
| Element_ID | Element | Transaction_Date | Transaction_Quantity | Total_Inventory | Replenishment | Replenishment_Date |
|:----------:|:----------:|:----------------:|:--------------------:|:---------------:|:-------------:|:------------------:|
| | STOCK | | 5 | 5 | NULL | NULL |
| MO302 | Make_Order | 1/3/2019 | 1 | 6 | NULL | NULL |
| SO105 | Sale | 2/1/2019 | -1 | 5 | STOCK | NULL |
| SO106 | Sale | 2/1/2019 | -1 | 4 | STOCK | NULL |
| MO323 | Make_Order | 2/2/2019 | 1 | 5 | NULL | NULL |
| SO107 | Sale | 2/4/2019 | -1 | 4 | STOCK | NULL |
| SO191 | Sale | 2/5/2019 | -1 | 3 | STOCK | NULL |
| SO123 | Sale | 2/6/2019 | -1 | 2 | STOCK | NULL |
| SO166 | Sale | 3/1/2019 | -1 | 1 | MO302 | 1/3/2019 |
| SO819 | Sale | 3/5/2019 | -1 | 0 | MO323 | 2/2/2019 |
| SO603 | Sale | 3/10/2019 | -4 | -3 | MO460 | 3/18/2019 |
| MO400 | Make_Order | 3/15/2019 | 1 | -2 | NULL | NULL |
| MO459 | Make_Order | 3/15/2019 | 1 | -1 | NULL | |
| MO460 | Make_Order | 3/18/2019 | 1 | 0 | NULL | NULL |
| MO491 | Make_Order | 3/19/2019 | 1 | 1 | NULL | NULL |
| MO715 | Make_Order | 4/1/2019 | 3 | 4 | NULL | NULL |
| SO100 | Sale | 4/2/2019 | -1 | 3 | MO491 | 3/19/2019 |
| SO322 | Sale | 4/3/2019 | -1 | 2 | MO715 | 4/1/2019 |
| SO874 | Sale | 4/4/2019 | -1 | 1 | MO715 | 4/1/2019 |
| SO222 | Sale | 4/5/2019 | -1 | 0 | MO715 | 4/1/2019 |
| MO999 | Make_Order | 4/5/2019 | 1 | 1 | NULL | NULL |
| SO999 | Sale | 4/6/2019 | -1 | 0 | SO999 | 4/5/2019 |
The ruleset would essentially be:
For a given requirement (a negative transaction quantity of arbitrary value), find which replenishment (a positive transaction quantity of arbitrary value) satisfies it.
Stock is assigned to the first requirements until it runs out. NOTE
-- it could be the case that stock does not exist, so this only applies IF stock does exist
Then, map replenishments to requirements based on the
Transaction_Date in ASC order
I am very confused on how to accomplish this. I imagine some pseudocode would look something like:
for curr in transaction_quantity:
if curr < 0:
if stock.exists() and stock.notempty():
fill in data from that
else:
find next replenishment
fill in data from that
else:
next
Right now, I have this so far, but I know that it will not run. I am very confused on where to go from here. I have tried looking at posts like this, but that did not have an answer. I then tried looking up CURSOR, but that was very confusing to me and I am unsure how I can apply that to this problem.
/****** WiP Script ******/
SELECT
[jerry].[dbo].[purchases_new].*,
CASE WHEN Transaction_Quantity < 0 THEN -- (SELECT Element_ID FROM the_current_row WHERE transaction_quantity > 0)
ELSE NULL AS "Replenishment",
-- (SELECT Transaction_Date FROM [jerry].[dbo].[purchases_new] WHERE Element_ID
-- Not sure how to grab the correct date of the element id from the column before
FROM
[jerry].[dbo].[purchases_new]
Any assistance is appreciated. I have been pulling my hair out on this problem. The comments contain additional information.
NOTE - I have continually tried to update this question as users have requested more information.
Here is one attempt. You will need to modify if with another layer of abstraction for offsets if you need to support transaction increments/decrements > 1. It basically aligns the order of sales with the order of debits and then uses that as join back to the main dataset.
Sql Fiddle
The idea is to put additions and subtractions into two sets, orderd chronologically by set, while also remembering order of each item back into the main list. This way, you can align each subtraction with the nearest addition. This is pretty straightforward when dealing with 1's.
Edit --> Dealing with values > 1.
Computing Transaction_Amount > (+/-)1 adds a little complexity, but still solvable. Now we need to stretch each addition and subtraction transaction set out by the Transaction_Amount, so the dataset is lengthened, however, the original algorithm will still be applied to a now longer dataset. This will allow for the recording of "partial fulfillments". So (12 A 5) would equate to (12 A 1), (12 A 1), (12 A 1), (12 A 1), (12 A 1). Now, when the subtractors are lengthened in similar fashion, (with all rows in the same order as the first of the sequence) the alignment will still work and addition and subtractions can be matched with the nearest neighbor(s).
DECLARE #T TABLE(Element_ID NVARCHAR(50),Element NVARCHAR(50), Transaction_Date DATETIME,Transaction_Quantity INT,Total_Inventory INT)
INSERT #T VALUES
('MO301','Make_Order','1/1/2019',5,1),
('MO302','Make_Order','1/3/2019',1,2),
('SO105','Sale','2/1/2019',-2,1),
('SO106','Sale','2/1/2019',-1,0),
('MO323','Make_Order','2/2/2019',1,1),
('SO107','Sale','2/4/2019',-1,0),
('SO191','Sale','2/5/2019',-1,-1),
('SO123','Sale','2/6/2019',-1,-2),
('SO166','Sale','3/1/2019',-1,-3),
('SO603','Sale','3/2/2019',-1,-4),
('MO400','Make_Order','3/15/2019',1,-3),
('MO459','Make_Order','3/15/2019',1,-2),
('MO460','Make_Order','3/18/2019',1,-1),
('MO491','Make_Order','3/19/2019',1,0)
;WITH Normalized AS
(
SELECT *, RowNumber = ROW_NUMBER() OVER (ORDER BY (SELECT 0)), IsAdd = CASE WHEN Transaction_Quantity>0 THEN 1 ELSE 0 END FROM #T
)
,ReplicateAmount AS
(
SELECT Element_ID, Element, Transaction_Date, Transaction_Quantity=ABS(Transaction_Quantity) ,Total_Inventory, RowNumber, IsAdd
FROM Normalized
UNION ALL
SELECT R.Element_ID, R.Element, R.Transaction_Date, Transaction_Quantity=(R.Transaction_Quantity - 1), R.Total_Inventory, R.RowNumber, R.IsAdd
FROM ReplicateAmount R INNER JOIN Normalized N ON R.RowNumber = N.RowNumber
WHERE ABS(R.Transaction_Quantity) > 1
)
,NormalizedAgain AS
(
SELECT Element_ID, Element, Transaction_Date, Transaction_Quantity=1, Total_Inventory, RowNumber = ROW_NUMBER() OVER (ORDER BY RowNumber), IsAdd FROM ReplicateAmount
)
,Additives AS
(
SELECT *, AddedOrder = ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM NormalizedAgain WHERE IsAdd=1
)
,Subtractions AS
(
SELECT Element_ID, Element, Transaction_Date, Transaction_Quantity=-1 , Total_Inventory, RowNumber, SubtractedOrder = ROW_NUMBER() OVER (ORDER BY (SELECT 0))FROM NormalizedAgain WHERE IsAdd=0
)
,WithTies AS
(
SELECT
S.RowNumber,
S.Element_ID,
BoughtFromRowNumber = A.RowNumber,
SoldToID =S.Element_ID,
BoughFromID=A.Element_ID,
S.Element,
S.Transaction_Date,
S.Transaction_Quantity,
S.Total_Inventory
FROM
Additives A
LEFT OUTER JOIN Subtractions S ON A.AddedOrder=S.SubtractedOrder
UNION
SELECT
A.RowNumber,
A.Element_ID,
BoughtFromRowNumber = S.RowNumber,
SoldToID = NULL,
BoughFromID=NULL,
A.Element,
A.Transaction_Date,
A.Transaction_Quantity,
A.Total_Inventory
FROM
Additives A
LEFT OUTER JOIN Subtractions S ON A.AddedOrder=S.SubtractedOrder
)
SELECT
T.RowNumber,
T.Element_ID,
T.Element,
T.Transaction_Date,
T.Transaction_Quantity,
T.Total_Inventory,
T2.SoldToID,
T.BoughFromID
FROM
WithTies T
LEFT OUTER JOIN WithTies T2 ON T2.BoughtFromRowNumber= T.RowNumber
WHERE
NOT T.RowNumber IS NULL
ORDER BY
T.RowNumber
I have huge data and sample of the table looks like below
+-----------+------------+-----------+-----------+
| Unique_ID | Date | RowNumber | Flag_Date |
+-----------+------------+-----------+-----------+
| 1 | 6/3/2014 | 1 | 6/3/2014 |
| 1 | 5/22/2015 | 2 | NULL |
| 1 | 6/3/2015 | 3 | NULL |
| 1 | 11/20/2015 | 4 | NULL |
| 2 | 2/25/2014 | 1 | 2/25/2014 |
| 2 | 7/31/2014 | 2 | NULL |
| 2 | 8/26/2014 | 3 | NULL |
+-----------+------------+-----------+-----------+
Now I need to check if the difference between Date in 2nd row and Flag_date in 1st row. If the difference is more than 180 then 2nd row Flag_date should be updated with the date in 2nd row else it needs to be updated by Flag_date in 1st Row. And same rule follows for all rows with same unique_ID
update a
set a.Flag_Date=case when DATEDIFF(dd,b.Flag_Date,a.[Date])>180 then a.[Date] else b.Flag_Date end
from Table1 a
inner join Table1 b
on a.RowNumber=b.RowNumber+1 and a.Unique_ID=b.Unique_ID
The above update query when executed once, only the second row under each Unique_ID gets updated and result looks like below
+-----------+------------+-----------+------------+
| Unique_ID | Date | RowNumber | Flag_Date |
+-----------+------------+-----------+------------+
| 1 | 2014-06-03 | 1 | 2014-06-03 |
| 1 | 2015-05-22 | 2 | 2015-05-22 |
| 1 | 2015-06-03 | 3 | NULL |
| 1 | 2015-11-20 | 4 | NULL |
| 2 | 2014-02-25 | 1 | 2014-02-25 |
| 2 | 2014-07-31 | 2 | 2014-02-25 |
| 2 | 2014-08-26 | 3 | NULL |
+-----------+------------+-----------+------------+
And I need to run four times to achieve my desired result
+-----------+------------+-----------+------------+
| Unique_ID | Date | RowNumber | Flag_Date |
+-----------+------------+-----------+------------+
| 1 | 2014-06-03 | 1 | 2014-06-03 |
| 1 | 2015-05-22 | 2 | 2015-05-22 |
| 1 | 2015-06-03 | 3 | 2015-05-22 |
| 1 | 2015-11-20 | 4 | 2015-11-20 |
| 2 | 2014-02-25 | 1 | 2014-02-25 |
| 2 | 2014-07-31 | 2 | 2014-02-25 |
| 2 | 2014-08-26 | 3 | 2014-08-26 |
+-----------+------------+-----------+------------+
Is there a way where I can run update only once and all the rows are updated.
Thank you!
If you are using SQL Server 2012+, then you can use lag():
with toupdate as (
select t1.*,
lag(flag_date) over (partition by unique_id order by rownumber) as prev_flag_date
from table1 t1
)
update toupdate
set Flag_Date = (case when DATEDIFF(day, prev_Flag_Date, toupdate.[Date]) > 180
then toupdate.[Date] else prev_Flag_Date
end);
Both this version and your version can take advantage of an index on table1(unique_id, rownumber) or, better yet, table1(unique_id, rownumber, flag_date).
EDIT:
In earlier versions, this might have better performance:
with toupdate as (
select t1.*, t2.flag_date as prev_flag_date
from table1 t1 outer apply
(select top 1 t2.flag_date
from table1 t2
where t2.unique_id = t1.unique_id and
t2.rownumber < t1.rownumber
order by t2.rownumber desc
) t2
)
update toupdate
set Flag_Date = (case when DATEDIFF(day, prev_Flag_Date, toupdate.[Date]) > 180
then toupdate.[Date] else prev_Flag_Date
end);
The CTE can make use of the same index -- and it is important to have the index. The reason for the better performance is because your join on row_number() cannot use an index on that field.
so let me start will the basic table layout for all tables involved:
#zip_code_time_zone
+----+----------+-----------+
| id | zip_code | time_zone |
+----+----------+-----------+
| 1 | 00544 | -1 |
| 2 | 00601 | -3 |
| 3 | 00602 | 0 |
| 4 | 00603 | -3 |
| 5 | 00604 | 0 |
+----+----------+-----------+
#pricing_record
+------+---------------+--------------------+
| id | location_code | service_center_zip |
+------+---------------+--------------------+
| 7119 | TX725 | 79714 |
| 7121 | TX734 | 75409 |
| 7122 | TX737 | 78019 |
| 7124 | TX742 | 75241 |
| 7126 | TX751 | 77494 |
+------+---------------+--------------------+
#transaction_record
+----+-----------------+------------------+--------------+--------------+
| id | truck_stop_code | create_date | gps_verified | central_time |
+----+-----------------+------------------+--------------+--------------+
| 1 | CA428 | 05/01/2015 14:52 | 0 | NULL |
| 2 | CA343 | 05/01/2015 19:10 | 0 | NULL |
| 3 | CA223 | 05/01/2015 09:28 | 0 | NULL |
| 4 | CA721 | 05/01/2015 07:55 | 0 | NULL |
| 5 | MN336 | 05/01/2015 06:46 | 0 | NULL |
+----+-----------------+------------------+--------------+--------------+
When I was working on this project an issue was noticed with the create_date column in transaction_record. It needs to be converted to central time, so I wrote an update query, but I have been unable to successfully set the central_time column. My query is below:
query
UPDATE t
SET t.central_time = DATEADD(hour, z.time_zone,CONVERT(DATETIME, t.create_date, 120))
FROM eagle_devel.dbo.zip_code_time_zone z
INNER JOIN eagle_devel.dbo.pricing_record p ON z.zip_code = p.service_center_zip
INNER JOIN eagle_devel.dbo.transaction_record t ON t.truck_stop_code = p.location_code
This is what i get when I run the query
(0 row(s) affected)
NOTES
The time_zone column in #zip_code_time_zone is not the standard UTC it is the difference to calculate to central
I am still working on this as we speak, just looking for some extra assistance to see if someone else can fix it faster than myself.
Try like this instead with little changes, table you are updating should be in FROM clause and then adjust the JOIN accordingly
UPDATE t
SET t.central_time = DATEADD(hour, z.time_zone,CONVERT(DATETIME, t.create_date, 120))
FROM eagle_devel.dbo.transaction_record t
INNER JOIN eagle_devel.dbo.pricing_record p ON t.truck_stop_code = p.location_code
INNER JOIN eagle_devel.dbo.zip_code_time_zone z ON z.zip_code = p.service_center_zip