Delete records with duplicates and join in another table - sql

I need to write a query (Microsoft SQL Server) to delete duplicates in the table Vehicle that have Vehicle.CarId = Car.CarId and having the same concatenation (CarId, CounterLimit, Kilometers).
Table Car:
CarId
-----
11111
Table Vehicle:
VehicleId CarId CounterLimit Kilometers
-----------------------------------------------------
1 11111 250 120000
2 23456 300 150000
3 11111 250 120000 (record duplicated with 1, should be deleted)
Could you please help me?

Delete rows with lesser VehicleId
delete v
from Vehicle v
where exists (
select 1
from Vehicle v2
where v2.VehicleId > v.VehicleId
and v2.CarId = v.CarId and v2.CounterLimit = v.CounterLimit and v2.Kilometers = v.Kilometers)
To just query the table
select max(vehicleid) vehicleid, carid, CounterLimit, Kilometers
from Vehicle
group by carid, CounterLimit, Kilometers

Joining the table
creating the rank based on carid,counter limit, kilometer. If all three are same it is considered as duplicate. If you need to add more or less number of columns in this criteria you can adjust this part
next we take just one of the above row , meaning we eliminate the duplicates using rank_1 = 1
with rank as (
select
vehicle.vehicleid,
vehicle.carid,
vehicle.CounterLimit,
vehicle.Kilometers,
row_number() over(partition by vehicle.carid,vehicle.CounterLimit, vehicle.Kilometers order by vehicle.vehicleid) as rank_
from a vehicle
left join car
on Vehicle.CarId =car.carid
)
select * from rank where rank_ = 1

Related

Last record per transaction

I am trying to select the last record per sales order.
My query is simple in SQL Server management.
SELECT *
FROM DOCSTATUS
The problem is that this database has tens of thousands of records, as it tracks all SO steps.
ID SO SL Status Reason Attach Name Name Systemdate
22 951581 3 Processed Customer NULL NULL BW 2016-12-05 13:33:27.857
23 951581 3 Submitted Customer NULL NULL BW 2016-17-05 13:33:27.997
24 947318 1 Hold Customer NULL NULL bw 2016-12-05 13:54:27.173
25 947318 1 Invoices Submit Customer NULL NULL bw 2016-13-05 13:54:27.300
26 947318 1 Ship Customer NULL NULL bw 2016-14-05 13:54:27.440
I would to see the most recent record per the SO
ID SO SL Status Reason Attach Name Name Systemdate
23 951581 4 Submitted Customer NULL NULL BW 2016-17-05 13:33:27.997
26 947318 1 Ship Customer NULL NULL bw 2016-14-05 13:54:27.440
Well I'm not sure how that table has two Name columns, but one easy way to do this is with ROW_NUMBER():
;WITH cte AS
(
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY SO ORDER BY Systemdate DESC)
FROM dbo.DOCSTATUS
)
SELECT ID, SO, SL, Status, Reason, ..., Systemdate
FROM cte WHERE rn = 1;
Also please always reference the schema, even if today everything is under dbo.
I think you can keep it this simple:
SELECT *
FROM DOCSTATUS
WHERE ID IN (SELECT MAX(ID)
FROM DOCSTATUS
GROUP BY SO)
You want only the maximum ID from each SO.
An efficient method with the right index is a correlated subquery:
select t.*
from t
where t.systemdate = (select max(t2.systemdate) from t t2 where t2.so = t.so);
The index is on (so, systemdate).

get max of max in select function

so I have 3 tables :
parkingZone -
ZID - zone id
Name - name of the zone
maxprice - max price of the parking zone
pricePerHour
carParking -
CID - the id of the car which parking
StartTime - start time of parking
EndTime - end time of parking
ParkingZoneID - zone ID (same as ZID in parkingzone)
Cost - how much the paking costed
Cars -
CID - same as CID in carParking
ID - ID of who owns the car
cellPhone - cellPhone of who ownsthe car
now I need to find the ID and CID of who has the max "cost" of the max "maxprice",
In other words, I need to find the ZID of the maximum "maxprice"
and then to find the ID and CID of the maximum "cost" related to "ZID"
so I managed to find all the CID that relates to the ZID:
select CarParking.CID, CarParking.Cost
from CarParking
inner join (select ParkingArea.AID
from ParkingArea
inner join(
select max(ParkingArea.maxpriceperday) maxpriceperday
from ParkingArea
)maxrow on maxrow.maxpriceperday = ParkingArea.maxpriceperday)maxCid on maxCid.AID= CarParking.ParkingAreaID
but how can I get the maximum cost, and then the CID AND ID from Cars table?
important note - there can be more then one max both in "maxpriceperday" and "Cost"
which means there could be more then one ZID with maxpriceperday(if they are equal)
and more then one maximum CID to each of those ZID (if the costs are equal).
so using "TOP" or "LIMIT" will not work.
for example:
how can I accomplish that?
thanks
This would be my approach:
First, select all ZID's with maxprice using a dense_rank. Next, use a second dense_rank to get all CID and with the highest cost from the selected ZID's. Finally, use the found CID's to get the Car-data.
That gives the CID's and ID's of all cars that have the highest (equal) cost in all lots with the highest maxprice.
If the dense_rank is new to you, you can read about it here
Gathered in one query:
SELECT CID
, ID
FROM Cars AS C
INNER JOIN (
SELECT CID
, Cost
, DENSE_RANK() over (ORDER BY Cost DESC) AS orderedCosts
FROM carParking AS CP
INNER JOIN (SELECT ZID
, DENSE_RANK() over (ORDER BY maxprice DESC) AS orderedMaxprice
FROM ParkingArea
) AS PA
ON PA.ZID= CP.ParkingAreaID
AND orderedMaxprice = 1
) as cars_most_costs
ON cars_most_costs.CID = C.CID
AND cars_most_costs.orderedCosts = 1
A dense_rank works like this:
ZID | maxprice| dense_rank
1 | 1000 | 1
3 | 1000 | 1
2 | 500 | 2
4 | 400 | 3
Using your paper example:
First step gets ZID 1 and 3, which both have the highest maxprice.
Next step gets CID 1010 and 1011, which are the cars with the higest cost on parkingzoneID's 1 and/or 3.
Final step returns CID/ID combo's 1010/2000 and 1011/2001.
The result you provided is actually wrong, because CID 1014 has a cost of 10 while the other two have 20.
If you meant max cost per parkingzoneID, then the question was not very clear, but you only have to change one line:
, DENSE_RANK() over (PARTITION BY ZID ORDER BY Cost DESC) AS orderedCosts
This will also return car 1014/2004

update in oracle sql : multiple rows in 1 table

I am new to SQL and I am no good with more advanced queries and functions.
So, I have this 1 table with sales:
id date seller_name buyer_name
---- ------------ ------------- ------------
1 2015-02-02 null Adrian
1 2013-05-02 null John B
1 2007-11-15 null Chris F
2 2014-07-12 null Jane A
2 2011-06-05 null Ted D
2 2010-08-22 null Maryanne A
3 2015-12-02 null Don P
3 2012-11-07 null Chris T
3 2011-10-02 null James O
I would like to update the seller_name for each id, by putting the buyer_name from previous sale as seller_name to newer sale date. For example, for on id 1 John B would then be seller in 2015-02-02 and buyer in 2013-05-02. Does that make sense?
P.S. This is the perfect case, the table is big and the ids are not ordered so neat.
merge into your_table a
using ( select rowid rid,
lead(buyer_name, 1) over (partition by id order by date desc) seller
from your_table
) b
on (a.rowid = b.rid )
when matched then update set a.seller_name= b.seller;
Explanation : Merge into statement performs different operations based on matched or not matched criterias. Here you have to merge into your table, in the using having the new values that you want to take and also the rowid which will be your matching key. The lead function gets the result from the next n rows depending on what number you specify after the comma. After specifying how many rows to jump you also specify on what part to work, which in your case is partitioned by id and ordered by date so you can get the seller, who was the previous buyer. Hope this clears it up a bit.
Either of the below query can be used to perform the desire action
merge into sandeep24nov16_2 table1
using(select rowid r, lag(buyer_name) over (partition by id order by "DATE" asc) update_value from sandeep24nov16_2 ) table2
on (table1.rowid=table2.r)
when matched then update set table1.seller_name=table2.update_value;
or
merge into sandeep24nov16_2 table1
using(select rowid r, lead(buyer_name) over (partition by id order by "DATE" desc) update_value from sandeep24nov16_2 ) table2
on (table1.rowid=table2.r)
when matched then update set table1.seller_name=table2.update_value;
select a.*,
lag(buyer_name, 1) over(partition by id order by sale_date) seller_name
from <your_table> a;

Get top values from two columns

Lets say I have a table like this:
id | peru | usa
1 20 10
2 5 100
3 1 5
How can I get the top values from peru and usa as well as the spefic ids. So that I get as result:
usa_id: 2 | usa: 100 | peru_id: 1 | peru: 20
Is this possible In one query? Or do I have to do two ORDER BY querys?
Im using postgresql
You can do this with some subqueries and a cross join:
select
u.id usa_id,
u.usa,
p.id peru_id,
p.peru
from
(select id, usa from mytable where usa=(select max(usa) from mytable) order by id limit 1) u
cross join (select id, peru from mytable where peru=(select max(peru) from mytable) order by id limit 1) p
;
In the case that there are multiple rows with the same max value (for usa or peru, independently), this solution will select the one with the lowest id (I've assumed that id is unique).
SELECT
t1.id as peru_id, t1.peru
, t2.id as usa_id, t2.usa
FROM tab1 t1, tab1 t2
ORDER BY t1.peru desc, t2.usa desc
limit 1
http://sqlfiddle.com/#!15/0c12f/6
As basicly what this does is a simple carthesian product - I guess that performance WILL be poor for large datasets.
on the fiddle it took 196ms for a 1k rows table. On 10k rows table - sqlFiddle hung up.
You can consider using MAX aggregate function in conjunction with ARRAY type. Check this out:
CREATE TEMPORARY TABLE _test(
id integer primary key,
peru integer not null,
usa integer not null
);
INSERT INTO _test(id, peru, usa)
VALUES
(1,20,10),
(2,5,100),
(3,1,5);
SELECT MAX(ARRAY[peru, id]) AS max_peru, MAX(array[usa, id]) AS max_usa FROM _test;
SELECT x.max_peru[1] AS peru, x.max_peru[2] AS peru_id, x.max_usa[1]
AS usa, x.max_usa[2] AS usa_id FROM (
SELECT MAX(array[peru, id]) AS max_peru,
MAX(array[usa, id]) AS max_usa FROM _test ) as x;

selecting more than one row of matching data

I need to select the number (cid) of a customer that has rented the same movie from 2 different branches. My tables are as follows:
RENTED
(cid, copyid)
12345 99999
12345 88888
COPY
(copyid, mid, bid)
99999 444 123
88888 444 456
So one customer (12345) has rented the same move (444) from two different branches (123, 456). I am not sure how to compare the values where in two different records, the values mid = mid but bid != bid. I tried to use 'some' and 'all' but this gives me no rows (code below)
select cid
from rented R join copy CP on R.copyid = CP.copyid
where CP.mid = all (select mid from copy where CP.mid = copy.mid) and CP.bid != some (select bid
from copy where CP.bid = copy.bid);
and my output should be
cid
12345
you could use the HAVING clause. The following query will list all customers who have ever rented the same movie several times:
SELECT r.cid
FROM rented r
JOIN copy p ON r.copyid = p.copyid
GROUP BY r.cid, p.mid
HAVING COUNT(DISTINCT c.bid) > 1
Using a single pass on each table:
select distinct(cid) from (
select cid, count(bid) over (partition by r.cid,c.mid) dist_branch
from rented r, copy c
where r.copyid = c.copyid)
where dist_branch > 1;