Deleting all but the most recent entry from single SQL table - mysql

I have a single SQL table that contains multiple entries for each customerID (some customerID's only have one entry which I want to keep). I need to remove all but the most recent entry per customerID, using the invoiceDate field as my marker.
So I need to go from this:
+------------+-------------+-----------+
| customerID | invoiceDate | invoiceID |
+------------+-------------+-----------+
| 1 | 1393995600 | xx |
| 1 | 1373688000 | xx |
| 1 | 1365220800 | xx |
| 2 | 1265220800 | xx |
| 2 | 1173688000 | xx |
| 3 | 1325330800 | xx |
+------------+-------------+-----------+
To this:
+------------+-------------+-----------+
| customerID | invoiceDate | invoiceID |
+------------+-------------+-----------+
| 1 | 1393995600 | xx |
| 2 | 1265220800 | xx |
| 3 | 1325330800 | xx |
+------------+-------------+-----------+
Any guidance would be greatly appreciated!

Write a query to select all the rows you want to delete:
SELECT * FROM t
WHERE invoiceDate NOT IN (
SELECT MAX(invoiceDate)
-- "FROM t AS t2" isn't supported by MySQL, see http://stackoverflow.com/a/14302701/227576
FROM (SELECT * FROM t) AS t2
WHERE t2.customerId = t.customerId
GROUP BY t2.customerId
)
This may take a long time on a big database.
If you're satisfied, change the query to a DELETE statement:
DELETE FROM t
WHERE invoiceDate NOT IN (
SELECT MAX(invoiceDate)
-- "FROM t AS t2" isn't supported by MySQL, see http://stackoverflow.com/a/14302701/227576
FROM (SELECT * FROM t) AS t2
WHERE t2.customerId = t.customerId
GROUP BY t2.customerId
)
See http://sqlfiddle.com/#!9/6e031/1
If you have multiple rows whose date is the most recent for the same customer, you would have to look for duplicates and decide which one you want to keep yourself. For instance, look at customerId 2 on the SQL fiddle link above.

Try out this one
with todelete as
(
select
CustomerId, InvoiceId, InvoiceDate, Row_Number() over (partition by CustomerId order by InvoiceDate desc) as Count
from DeleteDuplicate
)
delete from todelete
where count > 1

Let us asume that the table name is transaction_table.
create table test1 AS
select * from (
select * from transaction_table order by customerID, invoiceDate desc) temp
group by customerID
You will have the output data in test1 table.

delete from ex_4 where
rowid in
(select rowid
from ex_4 a
where to_date(invoicedate,'DDMMYYYY') = (select max(to_date(invoicedate,'DDMMYYYY')) from ex_4 b where a.customerid != b.customerid))
This is how it will be done in oracle.This query will delete all but most recently added row.Looking at your table structure i am assuming that the invoicedate column is varchar2 type so converting it to date used to_date function here

Related

Select only latest record for every employees and for specific employee in MySQL

I have a MySQL DB and in it there's a table with activity logs of employees.
+-------------------------------------------------+
| log_id | employee_id | date_time | action_type |
+-------------------------------------------------+
| 1 | 1 | 2015/02/03 | action1 |
| 2 | 2 | 2015/02/01 | action1 |
| 3 | 2 | 2017/01/02 | action2 |
| 4 | 3 | 2016/02/12 | action1 |
| 5 | 1 | 2016/10/12 | action2 |
+-------------------------------------------------+
And I would need 2 queries. First, to get for every employee his last action. So from this example table I would need to get row 3,4 and 5 with all columns. And second, get the latest action only for specified employee.
Any ideas how to achieve this? I'm using Spring Data JPA, but raw SQL Query would be also great.
Thank you in advance.
Ready for a fred ed...
SELECT x.*
FROM my_table x
JOIN
( SELECT employee_id
, MAX(date_time) date_time
FROM my_table
GROUP
BY employee_id
) y
ON y.employee_id = x.employee_id
AND y.date_time = x.date_time;
For your first query. Simply
SELECT t1.*
FROM tableName t1
WHERE t1.log_id = (SELECT MAX(t2.log_id)
FROM tableName t2
WHERE t2.employee_id = t1.employee_id)
For the second one
SELECT t1.*
FROM tableName t1
WHERE t1.employee_id=X and t1.log_id = (SELECT MAX(t2.log_id)
FROM tableName t2
WHERE t2.employee_id = t1.employee_id);
You can get the expected output by doing a self join
select a.*
from demo a
left join demo b on a.employee_id = b.employee_id
and a.date_time < b.date_time
where b.employee_id is null
Note it may return multiple rows for single employee if there are rows with same date_time you might need a CASE statement and another attribute to decide which row should be picked to handle this kind of situation
Demo

Joining multiple select sql statements (4 tables)

I need to join together 2 SQL statements and both of those statements work on their own. But I don't know how to combine both into 1 SQL statement.
I have two tables in 1st statement, TR120 and TR1201.
The SQL is this:
select
PRODUCT, PRICE, QUANTITY, INVOICE.DATE
from
TR1201
left join
(select
DATE, ID as INVOICE_ID, INVOICE
from TR120) as INVOICE on INVOICE.INVOICE_ID = ID
where
INVOICE.DATE >= '2016-06-01' and INVOICE.DATE <= '2016-06-30'
This returns a list of all the products I sold, with price, quantity and date of sales in a specific time frame from 01-06-16 till 30-06-16.
Now I need to find out the latest price that I bought product for in different two tables TR100 and TR1001 based on the product and date of sale from the 1st SQL statement.
select
PRODUCT, PRICE, SUP.DATE
from
TR1001
left join
(select
DATE, ID as SUP_ID, SUP_INVOICE
from TR100) as SUP on SUP.SUP_ID = ID
This returns a list of all the products that I have bought with a price and a date. I only need last record from this query based on product and date of purchased.
TR120
ID | INVOICE | DATE
1 | 000001 |2016-06-05
2 | 000002 |2016-06-15
3 | 000003 |2016-06-25
TR1201
ID | PRODUCT | PRICE A | QUANTITY
1 | A | 2,00 | 5
2 | A | 2,00 | 2
3 | A | 2,00 | 1
TR100
ID | SUP_INVOICE | DATE
1 | 160001 | 2016-05-30
2 | 160002 | 2016-06-16
TR1001
ID | PRODUCT | PRICE B
1 | A | 0,5
2 | A | 0,7
The result I am trying to get is this:
PRODUCT | PRICE A (tr1201) | QUANTITY | DATE (tr100) | PRICE B (tr1001)
A | 2 | 5 | 2016-05-30 | 0,5
A | 2 | 2 | 2016-05-15 | 0,5
A | 2 | 1 | 2016-05-16 | 0,7
That is all I want to do :(
Have you tried first_value?
FIRST_VALUE ( [scalar_expression ] )
OVER ( [ partition_by_clause ] order_by_clause [ rows_range_clause ] )
it works like this:
select distinct id,
first_value(price) over (partition by id (,sup) order by date DESC (latest, ASC for oldest)) as last_price
from table;
Documentation can be found here: https://msdn.microsoft.com/en-us/library/hh213018.aspx
I don't have your tables so cannot test and therefore am providing advice only.
I think what you need is an Outer apply like this instead of joins
select
T1.Product
, T1.Price
, T2.DATE -- Alias this
, T2.Price -- Alias this
, T3.DATE -- Alias this
, T3.Price -- Alias this
from T1
OUTER APPLY (
select top 1
Date
,Price
from table2
WHERE ID = T1.Id AND product = T1.Product-- plus any other joins
ORDER BY Date desc
) as T2
OUTER APPLY (
select top 1
Date
,Price
from table3
WHERE ID = T1.Id AND product = T1.Product-- plus any other joins
ORDER BY Date desc
) as T3

How to calculate running total grouped by Order No

Trying to create a running total for orders in SQL Server 2008, similar to the below table (Order No & Order Total columns exist in my SQL Server table), tried using a recursive cte but my results were a running total for all orders, not grouped by order no. Any suggestions how to have the running total grouped by the order no? Thanks
---------------------------------------------------------
| Order No. | Order Total | Running Total for Order No |
---------------------------------------------------------
| 1 | $10,000 | $10,000 |
---------------------------------------------------------
| 1 | -$5,000 | $5,000 |
---------------------------------------------------------
| 1 | $3,000 | $8,000 |
---------------------------------------------------------
| 2 | $2,500 | $2,500 |
---------------------------------------------------------
| 2 | $5,000 | $7,500 |
---------------------------------------------------------
| 2 | $4,000 | $11,000 |
---------------------------------------------------------
I would do this is with an Instead of Insert Trigger. The trigger would subtract/add from the groups first value. Obviously this should of been done at the creation of the table but you could add it after you make table update.
Keep in mind in order for the below code to work, you would need a primary key on the Order table
CREATE TABLE Orders
(
id INT IDENTITY(0, 1) PRIMARY KEY
, orderNo INT
, orderTotal MONEY
, runningTotal MONEY
);
INSERT INTO Orders
VALUES
(1,10000,10000),
(1,-5000,5000),
(1,3000,8000),
(2,2500,2500),
(2,5000,7500),
(2,4000,11500);
GO
--CREATE TRIGGER
CREATE TRIGGER trg_RunningTotal ON Orders
INSTEAD OF INSERT
AS
BEGIN
DECLARE #PreviousTotal MONEY =
(
SELECT TOP 1
a.runningTotal
FROM Orders AS a
INNER JOIN INSERTED AS b ON a.orderNo = b.orderNo
WHERE a.orderno = b.Orderno
ORDER BY a.id DESC
);
INSERT INTO Orders
SELECT
orderno,
orderTotal,
(#PreviousTotal + orderTotal) AS runningTotal
FROM INSERTED;
END;
--Insert new record
INSERT INTO orders
VALUES
(1,1000,NULL);
--View newly added record
SELECT
*
FROM orders
WHERE orderno = 1;
You need to following query:
SELECT orderno,
SUM((CASE WHEN ISNUMERIC(ordertotal)=1
THEN CONVERT(MONEY,ordertotal) ELSE 0 END)
)
AS [Converted to Numeric]
FROM price group by orderno

Get second highest values from a table

I have a table like this:
+----+---------+------------+
| id | conn_id | read_date |
+----+---------+------------+
| 1 | 1 | 2010-02-21 |
| 2 | 1 | 2011-02-21 |
| 3 | 2 | 2011-02-21 |
| 4 | 2 | 2013-02-21 |
| 5 | 2 | 2014-02-21 |
+----+---------+------------+
I want the second highest read_date for particular 'conn_id's i.e. I want a group by on conn_id. Please help me figure this out.
Here's a solution for a particular conn_id :
select max (read_date) from my_table
where conn_id=1
and read_date<(
select max (read_date) from my_table
where conn_id=1
)
If you want to get it for all conn_id using group by, do this:
select t.conn_id, (select max(i.read_date) from my_table i
where i.conn_id=t.conn_id and i.read_date<max(t.read_date))
from my_table t group by conn_id;
Following answer should work in MSSQL :
select id,conn_id,read_date from (
select *,ROW_NUMBER() over(Partition by conn_id order by read_date desc) as RN
from my_table
)
where RN =2
There is an intresting article on use of rank functions in MySQL here : ROW_NUMBER() in MySQL
If your table design as ID - date matching (ie a big id always a big date), you can group by id, otherwise do the following:
$sql_max = '(select conn_id, max(read_date) max_date from tab group by 1) as tab_max';
$sql_max2 = "(select tab.conn_id,max(tab.read_date) max_date2 from tab, $sql_max
where tab.conn_id = tab_max.conn_id and tab.read_date < tab_max.max_date
group by 1) as tab_max2";
$sql = "select tab.* from tab, $sql_max2
where tab.conn_id = tab_max2.conn_id and tab.read_date = tab_max2.max_date2";

MySQL how to calculate after stock taking

Data tables in the following manner;
Firm | PartID | StockCount | Date | Type
-----------------------------------------------------------
1 | 71 | 5 | 2014-02-01 | Incoming Invoice
1 | 71 | -1 | 2014-02-09 | Send Invoice
1 | 71 | 10 | 2014-02-13 | Stocktaking ( !!! Of the Depot. )
1 | 71 | -1 | 2014-02-21 | Send Invoice
1 | 71 | 5 | 2014-02-28 | Incoming Invoice
This table is actually a stock is a fictionalized depiction of movement table. Counts in this table made ​​in the store, purchase and sales invoices include. In this way, entering the warehouse, from the warehouse and the warehouse will be collected in a table quantities actually counted. From the moment that made ​​the Census, stock values ​​should be calculated over the stated amount. Where the problem was coming.
How do I get the following result?
Firm | PartID | StockCount | Date | Type
-------------------------------------------------------
1 | 71 | 14 | NULL | NULL
You seem to want the sum of the stock after "stock taking", which I suspect is more normally called "doing inventory" in English.
select Firm, PartId, sum(StockCount) as StockCount, NULL as Date, NULL as Type
from table t
where Date >= (select max(Date)
from table t2
where t2.Firm = t.Firm and
t2.partid = t.partid and
t2.type = 'Stocktaking'
)
group by Firm, Partid;
If there may be no Stocktaking record, then go with a left join approach:
select Firm, PartId, sum(StockCount) as StockCount, NULL as Date, NULL as Type
from table t left join
(select Firm, PartId, max(Date) as maxDate
from table t
where t2.type = 'Stocktaking'
group by Firm, PartId
) as tfp
on t.Firm = tfp.Firm and t.PartId = tfp.PartId and t.Date >= tfp.MaxDate
group by t.Firm, t.PartId;
If I am reading it right:
SELECT firm, partid, count(stockCount) as stock_total
FROM yourtable
WHERE firm = 1
AND partid = 71
You'll need to group by if you want to select multiple parts, something like:
SELECT firm, partid, count(stockCount) as stock_total
FROM yourtable
WHERE firm = 1
GROUP BY partid
Try this
SELECT Firm,
PartID,
Count(StockCount),
Date AS NULL,
TYPE AS NULL
FROM TABLE
GROUP BY Firm,
PartID
Your explanation of the problem is unclear, but I assume it is what you want.
SELECT Firm, PartID, SUM(StockCount) as StockCount, NULL as Date, NULL as Type
FROM tbl T1
WHERE Date >= (SELECT Date FROM tbl T2
WHERE T2.Type = Stocktaking
AND T1.Firm =T2.Firm
AND T1.PartId = T2.PartId
)
GROUP BY Firm, PartID