How to display (recursive) data-set in a particular manner? - sql

my brain may not be working today... but I'm trying to get a dataset to be arranged in a particular way. It's easier to show what I mean.
I have a dataset like this:
CREATE TABLE #EXAMPLE (
ID CHAR(11)
, ORDER_ID INT
, PARENT_ORDER_ID INT
);
INSERT INTO #EXAMPLE VALUES
('27KJKR8K3TP', 19517, 0)
, ('27KJKR8K3TP', 10615, 0)
, ('27KJKR8K3TP', 83364, 19517)
, ('27KJKR8K3TP', 96671, 10615)
, ('TXCMK9757JT', 92645, 0)
, ('TXCMK9757JT', 60924, 92645);
SELECT * FROM #EXAMPLE;
DROP TABLE #EXAMPLE;
The PARENT_ORDER_ID field refers back to other orders on the given ID. E.g. ID TXCMK9757JT has order 60924 which is a child order of 92645, which is a separate order on the ID. The way I need this dataset to be arranged is like this:
CREATE TABLE #EXAMPLE (
ID CHAR(11)
, ORDER_ID INT
, CHILD_ORDER_ID INT
);
INSERT INTO #EXAMPLE VALUES
('27KJKR8K3TP', 19517, 19517)
, ('27KJKR8K3TP', 19517, 83364)
, ('27KJKR8K3TP', 10615, 10615)
, ('27KJKR8K3TP', 10615, 96671)
--, ('27KJKR8K3TP', 83364, 83364)
--, ('27KJKR8K3TP', 96671, 96671)
, ('TXCMK9757JT', 92645, 92645)
, ('TXCMK9757JT', 92645, 60924)
--, ('TXCMK9757JT', 60924, 60924)
;
SELECT * FROM #EXAMPLE;
DROP TABLE #EXAMPLE;
In this arrangement of the data set, instead of PARENT_ORDER_ID field there is CHILD_ORDER_ID, which basically lists every single ORDER_ID falling under a given ORDER_ID, including itself. I ultimately would like to have the CHILD_ORDER_ID field be the key for the data set, having only unique values (so that's why I've commented out the CHILD_ORDER_IDs that would only contain themselves, because they have a parent order ID which already contains them).
Any advice on how to achieve the described transformation of the data set would be greatly appreciated! I've tried recursive CTEs and different join statements but I'm not quite getting what I want. Thank you!

You can try to use CTE recursive first, then you will get a result to show all Id hierarchy then use CASE WHEN judgment the logic.
;WITH CTE AS (
SELECT ID,ORDER_ID,PARENT_ORDER_ID
FROM #EXAMPLE
WHERE PARENT_ORDER_ID = 0
UNION ALL
SELECT c.Id,e.ORDER_ID,e.PARENT_ORDER_ID
FROM CTE c
INNER JOIN #EXAMPLE e
ON c.ORDER_ID = e.PARENT_ORDER_ID AND c.Id = e.Id
)
SELECT ID,
(CASE WHEN PARENT_ORDER_ID = 0 THEN ORDER_ID ELSE PARENT_ORDER_ID END) ORDER_ID,
ORDER_ID CHILD_ORDER_ID
FROM CTE
ORDER BY ID
sqlfiddle

Related

sql subtraction on two different tables

I have two different tables, common column is truck_id.
I need to subtract two tables from each other to find the net amount.
The result I want:
truck_id
difference
35kd85
1500
35hh52
900
SELECT
(SELECT SUM(last_revenue) FROM (
SELECT DISTINCT last_revenue FROM
Expedition WHERE YEAR(departure_date) > 2020 AND truck_id = '31adc444'
UNION ALL SELECT last_revenue FROM
ChainingExpedition WHERE YEAR(departure_date) > 2020 AND truck_id = '31adc444'
)x
)-(SELECT SUM(price_dollar) FROM (
SELECT DISTINCT price_dollar FROM TruckMaintenanceExpense
WHERE YEAR(payment_date) > 2020 AND expense_type = 'çeker'
AND truck_id ='31adc444'
)x
) AS difference
SQL subtraction on two different tables
When I type truck_id in my query, I get the right result, but my goal is to draw as a list.
Typically, I would create a list of all trucks that meet the criteria you are looking for. Then, I'll get a list of all trucks with revenue and a separate list of trucks with expense. Then you join those 3 tables together and do the math. You query was very hard to follow without good indenting and structure. Next time you ask a question, be sure to include sample data. You should be writing all the CREATE TABLE and INSERT INTO statements that I include in the EXAMPLE DATA section in the fiddle below.
--*****EXAMPLE DATA*****
CREATE TABLE Expedition (
truck_id nvarchar(50)
, last_revenue decimal(19,2)
, departure_date datetime
);
CREATE TABLE TruckMaintenanceExpense (
truck_id nvarchar(50)
, price_dollar decimal(19,2)
, payment_date datetime
);
INSERT INTO Expedition (truck_id, last_revenue, departure_date)
VALUES ('35kd85', 2000.00, '2020-1-1')
, ('35kd85', 3500.00, '2020-1-1')
, ('35hh52', 300.00, '2020-1-1')
, ('35hh52', 258.98, '2020-1-1')
;
INSERT INTO TruckMaintenanceExpense (truck_id, price_dollar, payment_date)
VALUES ('35kd85', 9865.23, '2020-2-1')
, ('35kd85', 321.54, '2020-2-1')
, ('35hh52', 159.78, '2020-2-1')
, ('35hh52', 598.77, '2020-2-1')
;
--*****END EXAMPLE DATA*****
--Create a list of all truck_ids. It would be more helpful
--if you had a table that defined all the trucks (i.e. dbo.trucks).
WITH AllTrucks as (
SELECT truck_id
FROM TruckMaintenanceExpense
UNION ALL
SELECT truck_id
FROM Expedition
)
SELECT DISTINCT
a.truck_id
--Use ISNULL to make sure we have 0.00 if the truck is missing
--either revenue or expense.
, ISNULL(tRev.total_revenue,0) - ISNULL(tExp.total_expense,0) as difference
--Get the list of truck_ids. Use SELECT DISTINCT to elimiate duplicates.
FROM AllTrucks as a
--Get a list of all trucks with Expedition reveue.
LEFT OUTER JOIN (
SELECT
e.truck_id
, YEAR(e.departure_date) as [year]
, SUM(e.last_revenue) as total_revenue
FROM Expedition as e
WHERE e.departure_date >= '2020-1-1 00:00:00'
AND e.departure_date < '2021-1-1 00:00:00'
GROUP BY e.truck_id, YEAR(departure_date)
) as tRev
ON tRev.truck_id = a.truck_id
--Get a list of all trucks with maintenance expenses.
LEFT OUTER JOIN (
SELECT
tme.truck_id
, YEAR(tme.payment_date) as [year]
, SUM(tme.price_dollar) as total_expense
FROM TruckMaintenanceExpense as tme
WHERE tme.payment_date >= '2020-1-1 00:00:00'
AND tme.payment_date < '2021-1-1 00:00:00'
GROUP BY tme.truck_id, YEAR(payment_date)
) as tExp
ON tExp.truck_id = a.truck_id
;
truck_id
difference
35hh52
-199.57
35kd85
-4686.77
fiddle

How to get last data in double data and delete the other with query

I have the data in table A with double or more. And i want get the last data input and delete the old data. How?
I try select with distinc and inner join, but when execute to delete the old and last data is include. so i have some issue.
Select * from A where po in (select max(po) from B)
The result is data invalid.
First i make new table result from distinc table A.
create table c AS
select distinct po, plan_ref from A group by po, plan_ref
After that, copy the table A. Let say it begin table B.
delete all the data in table A.
`INSERT INTO A (id, po
, plan_ref
, cust_order
, cust_code
, cust_name
, destination
, art_no
, art_name
, cust_reqdate
, posdd
, podd
, ship_date
, container
, ship
, plant_cell
, cbm
, remark
, upload_by
, upload_date)
select MAX(a.id), MAX (a.po)
, MAX(a.plan_ref)
, MAX(a.cust_order)
, MAX(a.cust_code)
, MAX(a.cust_name)
, MAX(a.destination)
, MAX(a.art_no)
, MAX(a.art_name)
, MAX(a.cust_reqdate)
, MAX(a.posdd)
, MAX(a.podd)
, MAX(a.ship_date)
, MAX(a.container)
, MAX(a.ship)
, MAX(a.plant_cell)
, MAX(a.cbm)
, MAX(a.remark)
, MAX(a.upload_by)
, MAX(a.upload_date) from C b
inner join B a on a.plan_ref = b.plan_ref
AND a.po = b.po GROUP BY a.po`
If you want to delete all but the maximum po (as suggested by your code), then you can do:
delete from a
where po < (select max(a2.po) from a a2);
More commonly, you would want to keep the maximum po based on some other column. For that, use a correlated subquery:
delete from a
where po < (select max(a2.po) from a a2 where a2.? = a.?); -- ? is for the grouping column

Query to determine cumulative changes to records

Given the following table containing the example rows, I’m looking for a query to give me the aggregate results of changes made to the same record. All changes are made against a base record in another table (results table), so the contents of the results table are not cumulative.
Base Records (from which all changes are made)
Edited Columns highlighted
I’m looking for a query that would give me the cumulative changes (in order by date). This would be the resulting rows:
Any help appreciated!
UPDATE---------------
Let me offer some clarification. The records being edited exist in one table, let's call that [dbo].[Base]. When a person updates a record from [dbo].[Base], his updates go into [dbo].[Updates]. Therefore, a person is always editing from the base table.
At some point, let's say once a day, we need to calculate the sum of changes with the following rule:
For any given record, determine the latest change for each column and take the latest change. If no change was made to a column, take the value from [dbo].[Base]. So, one way of looking at the [dbo].[Updates] table would be to see only the changed columns.
Please let's not discuss the merits of this approach, I realize it's strange. I just need to figure out how to determine the final state of each record.
Thanks!
This is dirty, but you can give this a shot (test here: https://rextester.com/MKSBU15593)
I use a CTE to do an initial CROSS JOIN of the Base and Update tables and then a second to filter it to only the rows where the IDs match. From there I use FIRST_VALUE() for each column, partitioned by the ID value and ordered by a CASE expression (if the Base column value matches the Update column value then 1 else 0) and the Datemodified column to get the most recent version of the each column.
It spits out
CREATE TABLE Base
(
ID INT
,FNAME VARCHAR(100)
,LNAME VARCHAR(100)
,ADDRESS VARCHAR(100)
,RATING INT
,[TYPE] VARCHAR(5)
,SUBTYPE VARCHAR(5)
);
INSERT INTO dbo.Base
VALUES
( 100,'John','Doe','123 First',3,'Emp','W2'),
( 200,'Jane','Smith','Wacker Dr.',2,'Emp','W2');
CREATE TABLE Updates
(
ID INT
,DATEMODIFIED DATE
,FNAME VARCHAR(100)
,LNAME VARCHAR(100)
,ADDRESS VARCHAR(100)
,RATING INT
,[TYPE] VARCHAR(5)
,SUBTYPE VARCHAR(5)
);
INSERT INTO dbo.Updates
VALUES
( 100,'1/15/2019','John','Doe','123 First St.',3,'Emp','W2'),
( 200,'1/15/2019','Jane','Smyth','Wacker Dr.',2,'Emp','W2'),
( 100,'1/17/2019','Johnny','Doe','123 First',3,'Emp','W2'),
( 200,'1/19/2019','Jane','Smith','2 Wacker Dr.',2,'Emp','W2'),
( 100,'1/20/2019','Jon','Doe','123 First',3,'Cont','W2');
WITH merged AS
(
SELECT b.ID AS IDOrigin
,'1/1/1900' AS DATEMODIFIEDOrigin
,b.FNAME AS FNAMEOrigin
,b.LNAME AS LNAMEOrigin
,b.ADDRESS AS ADDRESSOrigin
,b.RATING AS RATINGOrigin
,b.[TYPE] AS TYPEOrigin
,b.SUBTYPE AS SUBTYPEOrigin
,u.*
FROM base b
CROSS JOIN
dbo.Updates u
), filtered AS
(
SELECT *
FROM merged
WHERE IDOrigin = ID
)
SELECT distinct
ID
,FNAME = FIRST_VALUE(FNAME) OVER (PARTITION BY ID ORDER BY CASE WHEN FNAME = FNAMEOrigin THEN 1 ELSE 0 end, datemodified desc)
,LNAME = FIRST_VALUE(LNAME) OVER (PARTITION BY ID ORDER BY CASE WHEN LNAME = LNAMEOrigin THEN 1 ELSE 0 end, datemodified desc)
,ADDRESS = FIRST_VALUE(ADDRESS) OVER (PARTITION BY ID ORDER BY CASE WHEN ADDRESS = ADDRESSOrigin THEN 1 ELSE 0 end, datemodified desc)
,RATING = FIRST_VALUE(RATING) OVER (PARTITION BY ID ORDER BY CASE WHEN RATING = RATINGOrigin THEN 1 ELSE 0 end, datemodified desc)
,[TYPE] = FIRST_VALUE([TYPE]) OVER (PARTITION BY ID ORDER BY CASE WHEN [TYPE] = TYPEOrigin THEN 1 ELSE 0 end, datemodified desc)
,SUBTYPE = FIRST_VALUE(SUBTYPE) OVER (PARTITION BY ID ORDER BY CASE WHEN SUBTYPE = SUBTYPEOrigin THEN 1 ELSE 0 end, datemodified desc)
FROM filtered
Don't you just want the last record?
select e.*
from edited e
where e.datemodified = (select max(e2.datemodified)
from edited e2
where e2.id = e.id
);

How to query newest item from table with duplicate items?

I have to deal with data that is being dumped to a "log" table within SQL Server. Unfortunately can't make changes. Basically a process is run daily which dumps some duplicate items into a table.
Table 1:
import_id: guid
import_at: datetime
Table 2:
item_id: guid
import_id: guid (foreign key)
item_url: varchar(1000)
item_name: varchar(50)
item_description: varchar(1000)
Sometimes Table 2 will have a duplicate item_url. I only want to get the list of item_id and item_url from the newest import.
The query below will return one row per item_url, the one with the latest import_at value:
WITH all_items AS (
SELECT
t1.import_id
, t1.import_at
, t2.item_id
, t2.item_url
, t2.item_name
, t2.item_description
, ROW_NUMBER() OVER(PARTITION BY item_url ORDER BY t1.import_at DESC) AS item_url_rank
FROM dbo.table1 AS t1
JOIN dbo.table1 AS t2 ON
t2.import_id = t1.import_id
)
SELECT
t1.import_id
, import_at
, item_id
, item_url
, item_name
, item_description
WHERE
item_url_rank = 1;

Find the most recent shipment for a product (sql subselect?)

I have three tables
shipment (shipment_id, shipping_date)
company_order (company_order_id, shipment_id, company_id)
company_order_item (company_order_item_id, company_order_id, product_id)
Several companies get together and aggregate orders from a single manufacturer. This aggregate order is called a "shipment". Companies order a selection of products in each shipment: so not all products will be present in any one shipment or for any one company.
How do I write an SQL query find the most recent shipment for each product_id ?
I've looked at
SQL Query - Get Most Recent Revision (much simpler case).
You need to get the max shipment date per product id and then retrieve the shipment detaisl
Something like
SELECT *
FROM (
SELECT coi.product_id,
MAX(s.shipping_date) MaxDate
FROM company_order_item coi INNER JOIN
company_order co ON coi.company_order_id = co.company_order_id INNER JOIN
shipment s ON co.shipment_id =s.shipment_id
GROUP BY coi.product_id
) sub INNER JOIN
company_order_item coi ON sub.product_id = coi.product_id INNER JOIN
company_order co ON coi.company_order_id = co.company_order_id INNER JOIN
shipment s ON co.shipment_id = s.shipment_id
AND s.shipping_date = sub.MaxDate
SQL Code to illustrate - (This is T-SQL and is SQL Server friendly, but i didn't have any mysql handy. The last query should with tiny modifications (to suit your table names) work nicely in MySQL as well.
My logic is to find the most recent company_order for each product_id. Once i have that i can just join the company_order_id to company_order, and i have the shipment_id for each most-recent company_order per product_id
DROP TABLE #shipment
DROP TABLE #company_order
DROP TABLE #company_order_item
CREATE TABLE #shipment
(
shipment_id INT ,
shipping_date INT
) ;
CREATE TABLE #company_order
(
company_order_id INT ,
shipment_id INT ,
company_id INT
) ;
CREATE TABLE #company_order_item
(
company_order_item_id INT ,
company_order_id INT ,
product_id INT
) ;
INSERT INTO #shipment
( shipment_id , shipping_date )
VALUES
( 1 , 1 ),
( 2 , 2 ),
( 3 , 3 )
INSERT INTO #company_order
( company_order_id , shipment_id , company_id )
VALUES
( 1 , 1 , 1 ),
( 2 , 2 , 1 ),
( 3 , 3 , 1 )
INSERT INTO #company_order_item
( company_order_item_id , company_order_id , product_id )
VALUES
( 1 , 1 , 1 ) ,
( 2 , 1 , 2 ),
( 2 , 2 , 2 ),
( 1 , 1 , 3 ),
( 1 , 3 , 4 )
SELECT
product_id ,
shipment_id
FROM
(
SELECT
product_id ,
MAX(company_order_id) AS company_order_id
FROM
#company_order_item
GROUP BY
product_id
) AS MostRecentProductInOrder
INNER JOIN #company_order
ON MostRecentProductInOrder.company_order_id = #company_order.company_order_id