Update only one row of duplicate rows in SQL [closed] - sql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
i have a problem. I have tried to search other questions but not working for my problem, so i try to explain it.
I have a table that has 7 columns with 4 primary keys:
Istituto, Filiale, Cdg, Progressivo, DataInserimento, Operatore, Testo
First 4 column are keys and there are sometime record with simil keys (same Istituto, Cdg and Progressivo) but same DataInserimento (that is a DATETIME field), i would found this record and change one (or more if there are more than two record with same date and Cdg) adding 100 ms for distinct date from each other.
For example:
Istituto Filiale cdg Progressivo DataInserimento Operatore Testo
1 12 456 1 12/11/2015 12:00:00:200 UGO QUALCOSA
1 123 456 1 12/11/2015 12:00:00:200 UGO QUALCOSA2
1 124 456 1 12/11/2015 12:00:00:200 UGO QUALCOSA3
I Would like this after query:
Istituto Filiale cdg Progressivo DataInserimento Operatore Testo
1 12 456 1 12/11/2015 12:00:00:200 UGO QUALCOSA
1 123 456 1 12/11/2015 12:00:00:300 UGO QUALCOSA2
1 124 456 1 12/11/2015 12:00:00:400 UGO QUALCOSA3
Can I solve this problem?

In this UPDATE you change dataInserimento adding a multiple of 100 ms in base of previous rows of your row if exists another row with the same 3 fields of primary key (except Filiale)
Try this:
UPDATE yourtable
SET dataInserimento = DATEADD(ms, 100 *
(SELECT COUNT(*)
FROM yourtable T3
WHERE T3.Istituto = yourtable.Istituto
AND T3.cdg = yourtable.cdg
AND T3.Progressivo = yourTable.Progressivo
AND T3.filiale < yourTable.filiale)
, dataInserimento)
WHERE EXISTS(
SELECT 'next'
FROM yourtable t2
WHERE T2.Istituto = yourtable.Istituto
AND T2.cdg = yourtable.cdg
AND T2.Progressivo = yourTable.Progressivo
AND T2.filiale < yourTable.filiale
)

You can do this:
UPDATE ToUpdate SET DataInserimento = SQ.NewDate
FROM TheTable ToUpdate
JOIN (
SELECT T.Istituto, T.Cdg, T.Progressivo, T.Filiale, DATEADD(ms, ROW_NUMBER() OVER (PARTITION BY T.Istituto, T.Cdg, T.Progressivo, T.DataInserimento ORDER BY T.Filiale) * 100, T.DataInserimento) AS NewDate
FROM (
SELECT Istituto, Cdg, Progressivo, DataInserimento, MIN(Filiale) AS MINFiliale
FROM TheTable
GROUP BY Istituto, Cdg, Progressivo, DataInserimento
HAVING COUNT(*) > 0
) AS Groups
JOIN TheTable T ON Groups.Istituto = T.Istituto AND Groups.Cdg = T.Cdg AND Groups.Progressivo = T.Progressivo AND Groups.DataInserimento = T.DataInserimento
WHERE T.Filiale <> MINFiliale
) SQ ON SQ.Istituto = ToUpdate.Istituto AND SQ.Cdg = ToUpdate.Cdg AND SQ.Progressivo = ToUpdate.Progressivo AND SQ.Filiale = ToUpdate.Filiale

Related

How to use group by with case statement [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 11 months ago.
Improve this question
I have a table with following fields
CREATE TABLE Tblstock
( ID int , SlNo int, Storage varchar(10), stock int);
insert into Tblstock values
(1, 1, 'STORE', 100),
(2, 1, 'Floor 1', 20),
(3, 2, 'STORE', 2000),
(4, 2, 'Floor 1', 40);
I have to dynamically update the left over quantity in store after it got consumed on floor1, I have written a code to calculate qty in store using below mentioned query,
SELECT (
(SELECT CASE WHEN COUNT(B.SlNo) > 1 OR B.Storage = 'STORE' THEN SUM(B.Stock)END FROM TblStock B GROUP BY B.SlNo) -
(SELECT CASE WHEN COUNT(B.SlNo) > 1 OR B.Storage <> 'STORE' THEN SUM(B.Stock)END FROM TblStock B GROUP BY B.SlNo))
However it is not generating the desired result and throwing error
Can anybody help to write it properly so that I get single value of remaining quantity in store
You just need a straight-forward grouping and conditional aggregation
SELECT
s.SlNo,
Total = SUM(CASE WHEN s.Storage = 'STORE' THEN s.Qty ELSE -s.Qty END)
FROM TblStock s
GROUP BY
s.SlNo;
db<>fiddle
Assuming what you are trying to do is to deduct the quantity (qty) in storage called store by the sum of the rest of the other storage. I could think of a query like this:
select *,
(Qty - (select sum(b.Qty) from tblstock as b
where b.Storage <> 'store'
and b.SINo = a.SINo
group by b.SINo)) as remainingQty
from tblstock as a
where a.Storage = 'store' group by a.SINo
The query above, with the following input:
ID
SINo
Storage
Qty
1
1
store
100
2
1
floor 1
20
3
1
floor 2
30
4
2
store
100
5
2
floor 1
40
6
2
floor 2
50
It produces the following output:
ID
SINo
Storage
Qty
remainingQty
1
1
store
100
50
4
2
store
100
10
You can find the SQLFiddle here.
Note:
If you are want to avoid subquery and have the urge to chug in join fiddle:
select a.id,
a.SINo,
a.Storage,
a.Qty,
c.Qty,
(a.Qty - c.Qty) as remainingQty
from tblstock as a
join
(select b.SINo,
sum(b.Qty) as Qty
from tblstock as b
where b.Storage <> 'store'
group by b.SINo) as c
on c.SINo = a.SINo
where a.Storage = 'store' group by a.SINo

update based on multiple rows in sql [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
PART LATESTPART RATE LATESTMONTHSALE status
A X 100 2019-06-01 N
B X 100 2019-07-01 N
C Y 200 2019-08-01 N
D Y 150 2019-08-01 N
E X 100 2019-09-01 N
update status as "Y" of PART when LATESTPART is same and RATE minimum
Eg. for PART C,D LATESTPART is same(Y) and rate of 'PART' D is minimum(150) then update part D status "Y".
If rate is same then check LATESTMONTHSALE. Update status of the PART having lastest month.
Eg. for PART A,B,E LATESTPART is same(X) and rate is also same then update PART E because 2019-09-01 is latest date.
i want result as.
PART LATESTPART RATE LATESTMONTHSALE status
A X 100 JUN_19 N
B X 100 JUL_19 N
C Y 200 AUG_19 N
D Y 150 AUG_19 Y
E X 100 SEP_19 Y
I think that you can do this with a correlated subquery that filters on the latest records per (part, latestpart) tuple and a not exists condition that filters on the record that has the lowest rate.
update mytable t set status = 'Y'
where
t.latestmonthsale = (
select max(t1.latestmonthsale)
from mytable t1
where t1.part = t.part and t1.latestpart = t.latestpart
)
and not exists (
select 1
from mytable t1
where
t1.part = t.part
and t1.latestpart = t.latestpart
and t1.latestmonthsale = t.latestmonthsale
and t1.rate < t.rate
)
In SQLServer, you can also do this with row_number() and an updatable cte:
with cte as (
select
status,
row_number()
over(partition by part, latestpart order by latestmonthsale desc, rate) rn
from mytable
)
update cte set status = 'Y' where rn = 1

How do I get the max records of a max subset in SQL [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have the following tables:
Training Occurrence
Id Training Id Due Date
5 1 09/01/2018
6 1 09/15/2018
7 2 09/01/2018
Training Occurrence User
Id Training Material Occurrence Id User Id
1 5 'Chad'
2 5 'Chad'
3 6 'Chad'
4 6 'Chad'
5 7 'Chad'
My query needs to get the newest Training Material Occurrence User record of the newest Training Material Occurrence table. So if I pass in the user 'Chad'
I would want to see:
Id Occurrence Id User Training Id Due Date
4 6 'Chad' 1 09/15/2018
5 7 'Chad' 2 09/01/2018
Here is my query:
SELECT tmou.*, tmo.TrainingMaterialId, tmo.DueDate
FROM dbo.TrainingMaterialOccurrenceUser as tmou
INNER JOIN dbo.TrainingMaterialOccurrence as tmo on
tmou.TrainingMaterialOccurrenceId = tmo.Id
AND tmou.Id IN (SELECT MAX(tmou.Id)
FROM dbo.TrainingMaterialOccurrenceUser as tmou
WHERE tmou.UserId = #UserId
AND tmou.TrainingMaterialOccurrenceId IN (SELECT MAX(tmo.Id) as occurrenceId
FROM dbo.TrainingMaterialOccurrence as tmo
WHERE tmo.Id IN (Select TrainingMaterialOccurrenceId FROM dbo.TrainingMaterialOccurrenceUser as tmou1 WHERE tmou1.UserId = #UserId)
GROUP BY tmo.TrainingMaterialId)
GROUP BY tmou.TrainingMaterialOccurrenceId)
As you can see this is a mess. Any ideas on how I can clean this up.
Rank your rows with ROW_NUMBER:
SELECT Id, TrainingMaterialOccurrenceId, UserId, TrainingMaterialId, DueDate
FROM
(
SELECT
tmou.Id,
tmou.TrainingMaterialOccurrenceId,
tmou.UserId,
tmo.TrainingMaterialId,
tmo.DueDate,
ROW_NUMBER() OVER(PARTITION BY tmo.TrainingMaterialId
ORDER BY tmo.DueDate DESC,
tmo.Id DESC,
tmou.TrainingMaterialOccurrenceId DESC,
tmou.Id DESC) AS rn
FROM dbo.TrainingMaterialOccurrenceUser as tmou
INNER JOIN dbo.TrainingMaterialOccurrence as tmo
ON tmo.Id = tmou.TrainingMaterialOccurrenceId
)
WHERE rn = 1;

SQL select column of attributes with latest date [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have a table with multiple tenants and some tenants have an other expiration date, the rest in the table is for every tenant the same. I want to select the tenant with only the latest expiration date.
This is my code:
SELECT DISTINCT
property.scode AS "M nr",
tenant.scode AS "Contract nr",
unit.scode AS "Unit",
commamendments.DTSTART AS "Starting date",
sqft.DTDATE AS "Expiry date",
sqft.DSQFT0 AS "Area"
FROM
property
LEFT JOIN unit ON unit.hproperty = property.hmy
LEFT JOIN unitxref ON unitxref.hunit = unit.hmy
LEFT JOIN commamendments ON commamendments.hmy = unitxref.hamendment
LEFT JOIN tenant ON tenant.hmyperson = commamendments.htenant
JOIN attributes ON attributes.HPROP = property.hmy
JOIN sqft ON sqft.hpointer = unit.hmy
WHERE property.scode = '481'
AND sqft.DSQFT0 != '0'
AND ('9/30/2017 12:00:00 AM' BETWEEN commamendments.DTSTART AND commamendments.DTEND)
ORDER BY commamendments.DTEND`
As output I want a table with
Mnr Contract nr Unit Starting date Expiry date Area
481 1 1 9-10-2017 12-31-2018 400
481 2 2 8-10-2017 12-31-2019 500
.....
What I now receive is:
Mnr Contract nr Unit Starting date Expiry date Area
481 1 1 9-10-2017 12-31-2018 400
481 1 1 9-10-2017 09-20-2018 400
481 2 2 8-10-2017 12-31-2019 500
481 2 2 8-10-2017 1-31-2018 500
.....
Since you didn't specify which RDBMS you are working on and the table schema, then you can do this:
SELECT t1.tenantId, t1.ExpiryDate
FROM tenants AS t1
INNER JOIN
(
SELECT tenantId, MAX(ExpiryDate) AS LatestExpiryDate
FROM tablename
GROUP BY tenantId
) AS t1 ON t1.tenantId = t2.tenantId, t1.ExpiryDate = t2.LatestExpiryDate;
The inner join will give the latest date for each tenant id, and then you can join with the original query to get only those with the latest date.
(You didn't specify the table schema so I had to guess the columns' names, but I hope you got the idea).
Use Row_Number() to find the latest record of your tenants
Select * from (
Select *,Row_number() over(Partition by Tenants order by expirationdate desc) as rn from tablea
) x
Where rn = 1

Multiple Insert, Update and Delete [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am having three tables
Present , History and Hold Table
By the end of the day I have to clear the entire present table data like
If there is an Id with the existing one in History table then I have to look at the balance and then subtract current balance from that table.
If balance- currentbalance < 0 then subtract the balance from history table make it zero and add a new row in history table with currentbalance-balance as balance
If there is no ID in history table and currentbalance > 0 move that record to hold table .
If currentbalance < = 0 change the date in the present table to next day. I just need a single query for all this.
If there is a record in hold table remove that record and place the latest record.
Every time when u update a row change the DATE column to current date apart from present table.
Present:
ID Current_Balance Date
1 2000 25-06-2014
2 1500 25-06-2014
3 5000 25-06-2014
2 6000 25-06-2014
4 -200 25-06-2014
History:
ID Balance Date
1 1500 24-06-2014
2 1600 24-06-2014
Hold Table:
ID Balance Date
3 125 24-06-2014
4 2000 24-06-2014
I want result like
Present:
ID Current_Balance Date
4 -200 26-06-2014
History:
Id Balance Date
1 0 25-06-2014
1 500 25-06-2014
2 100 25-06-2014
Hold:
ID Balance Date
3 5000 25-06-2014
4 2000 24-06-2014
I have written my code which is a bit complex. Can anyone give me optimum solution for this.
Use following query:
UPDATE Persent
SET current_Balance = 0,
Date = GETDATE()
OUTPUT Inserted.ID, Deleted.current_Balance, Deleted.Date
INTO #P
FROM History h
WHERE h.Id = Persent.ID
AND h.balance - Persent.current_balance < 0
INSERT INTO History (Id, Balance, Date)
SELECT p.Id, p.Current_Balance, p.Date
FROM #P p
MERGE Hold AS Destination
USING (SELECT * FROM Present WHERE Current_Balance>0) AS Source ON Destination.Id = Source.Id
WHEN NOT MATCHED THEN INSERT (Id, Balance, Date) VALUES (ID,Current_Balance,Date)
WHEN MATCHED THEN DELETE
UPDATE Persent
SET Date = DATEADD(DAY, 1, GETDATE())
WHERE Persent.current_balance <= 0