I have written a stored procedure that only allowed to have 100 rows with same CustomerPK, so if we want to insert row 101, the oldest row with the same CustomerPK needs to be deleted.
I'm sure there are several ways of doing this and I'm not sure which one is best. Here is the code for the procedure.
DECLARE
#TokenCount INT;
SELECT
#TokenCount = COUNT(*)
FROM
CustomerAuthTokens
WHERE
CustomerPK = #CustomerPK;
IF #TokenCount > 99
BEGIN
DELETE FROM CustomerAuthTokens
WHERE AuthToken IN (SELECT TOP(#TokenCount - 99) AuthToken
FROM CustomerAuthTokens
WHERE CustomerPK = #CustomerPK
ORDER BY TokenCreateTime ASC);
END
--Insert your row first
-- This will delete customer rows if there are more than 100 rows for that customer
;WITH cte as
(
SELECT row_number() over (partition by CustomerPK order by TokenCreateTime desc) rn
FROM CustomerAuthTokens
WHERE CustomerPK = #CustomerPK
)
DELETE CTE
WHERE rn > 100
Related
I have a table1: id int, id_2 int, date timestamp, vec float[]
And table2 : id int, vec float[]
My target is to create trigger on update of table1 which will take last 10 (by date) rows for id_2, take average of vectors by first axis(10 x N -> N) and write it to table2 under id = id_2.
My code:
CREATE OR REPLACE FUNCTION public.foo()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
WITH rows AS (
SELECT DISTINCT t1.id_2, t2.id, t2.vec, t2.date, DENSE_RANK() OVER (PARTITION BY t1.id_2 ORDER BY t2.date desc) AS counter
FROM new_table AS t1
LEFT JOIN table1 t2 ON t1.id_2 = t2.id_2
),
elements_average AS (
SELECT id_2, AVG(unnest::float) AS av
FROM rows,
unnest(vec) with ORDINALITY
WHERE counter < 11
GROUP BY id_2, ORDINALITY
ORDER BY ORDINALITY
),
avr AS (
SELECT id_2, array_agg(av::float) AS averages
FROM elements_average
GROUP BY id_2
)
UPDATE table2 SET vec = averages FROM avr WHERE table2.id = user_av.id_2;
RETURN NULL;
END;
$function$
;
CREATE TRIGGER foo_trigger AFTER
UPDATE
ON
public.table1 REFERENCING NEW TABLE AS new_table FOR EACH STATEMENT EXECUTE FUNCTION foo()
The problem: when I update few rows in table1 with different id_2 in one transactions a value in table2 becomes wrong. Not the average.
What's even more strange is that this code gives correct values in same situation:
...
avr AS (
SELECT id_2, array_agg(av::float) AS averages
FROM elements_average
GROUP BY id_2
),
strange_thing AS (
SELECT * from elements_average
)
UPDATE table2 SET vec = averages FROM avr WHERE table2.id = user_av.id_2;
RETURN NULL;
END;
$function$
;
So, small meaningless and unimportant SELECT changes the behavior of the function. Is it a bug of postgres or my fault?
I didn't find my case on the Internet. Tell me how i can delete duplicates if the values are in different columns.
I have a table with a lot of values, for example:
|Id1|Id2|
|89417980|89417978|
|89417980|89417979|
|89417978|89417980|
|89417979|89417980|
I need to exclude duplicates and leave in the answer only:
|Id1|Id2|
|89417980|89417978|
|89417980|89417979|
min/max does not work here, as the values may be different.
I tried to union/join tables on a table/exclude results with temporary tables, but in the end I come to the beginning.
Assuming id1 and id2 are primary keys columns you could try this
DECLARE #tbl table (id1 int, id2 int )
INSERT INTO #tbl
SELECT 89417980, 89417978
UNION SELECT 89417980, 89417979
UNION SELECT 89417978, 89417980
UNION SELECT 89417979, 89417980
SELECT * FROM #tbl
;WITH CTE AS (--Get comparable value as "cs"
SELECT
IIF(id1 > id2, CHECKSUM(id1, id2), CHECKSUM(id2,id1)) as cs
, id1
, id2
, ROW_NUMBER() OVER (order by id1, id2) as rn
FROM #tbl
)
, CTE2 AS ( --Get rows to keep
SELECT MAX (rn) as rn
FROM CTE
GROUP BY cs
HAVING COUNT(*) > 1
)
DELETE tbl -- Delete all except the rows to keep
FROM #tbl tbl
WHERE NOT EXISTS(SELECT 1
FROM CTE2
JOIN CTE ON CTE.rn = CTE2.rn
WHERE CTE.id1 = tbl.id1
AND CTE.id2 = tbl.id2
)
SELECT * FROM #tbl
How to I delete records from a table which is referenced in my query for example, below is my query which returns me the correct amount of results but I then want to delete those records from the same table that is referenced in the query.
;with cte as (select *,
row_number() over (partition by c.[Trust Discharge], c.[AE Admission], c.[NHS Number]
order by c.[Hospital Number]) as Rn,
count(*) over (partition by c.[Trust Discharge], c.[AE Admission], c.[NHS Number]) as cntDups
from CommDB.dbo.tblNHFDArchive as c)
Select * from cte
Where cte.Rn>1 and cntDups >1
as you can already select the rows by querying Select * from cte Where cte.Rn>1 and cntDups >1, you can delete them by running delete from your_table where unique_column in (Select unique_column from cte Where cte.Rn>1 and cntDups >1)
note that unique_column is a column in your table that cannot have duplicate values, and your_table is the table where the rows reside.
and don't forget to backup your table first if it's on production.
-- Create Sample data
Use AdventureWorks2012;
IF OBJECT_ID('TempTable1', 'U') IS NOT NULL
DROP TABLE TempTable1
-- Grab data from AdventureWorks2012
SELECT SOD.ProductId as ResourceID,
SOH.DueDate as DueDate,
SOD.OrderQty as DayIncrement,
Row_Number() over (PARTITION BY SOD.ProductID ORDER By SOH.DueDate) as JResourceNumber
INTO TempTable1
FROM Sales.SalesOrderHeader SOH
INNER JOIN Sales.SalesOrderDetail SOD
ON SOH.SalesOrderID = SOD.SalesOrderID
ORDER by ResourceID, JResourceNumber
-- Reduce records to 2637
IF OBJECT_ID('TempTable', 'U') IS NOT NULL
DROP TABLE TempTable
SELECT ResourceID, DueDate, DayIncrement, Row_Number() over (ORDER By ResourceID) as JRowNumber, GETDATE() as SchedDate
INTO TempTable
FROM TempTable1
WHERE JResourceNumber <= 10
--END create sample data
--
-- Calulate a rolling available date for ResourceId = Prev.SchedDate + Curr.DayIncrement
--
IF OBJECT_ID('FINALTABLE', 'U') IS NOT NULL
DROP TABLE FinalTable
SELECT Curr.ResourceID, Curr.DueDate, Curr.DayIncrement, Curr.JRowNumber as CurrRowNumber, Prev.JRowNumber as PrevJRowNumber,
Prev.SchedDate as ShouldBePrevSchedDate,
Case
WHEN Curr.ResourceID = Prev.ResourceID THEN DATEADD(DAY, Curr.DayIncrement, Prev.SchedDate)
ELSE GETDATE()
END AS SchedDate
-- This is the self join
FROM TempTable Curr
LEFT JOIN TempTable Prev ON Prev.JRowNumber = Curr.JRowNumber - 1
I have a table like below:
SuppID AreaID SuppNo SupName SupPrice
------------------------------------------------
1 3 526 ANC 100
1 3 985 JTT 200
3 4 100 HIK 300
In the above table, for same SuppID(1) and same AreaID(3), different SuppNo are there (526 & 985) in two different rows.
In this scenario , I'd like to make those two rows into a single row with SuppNo field as blank.
Also my output result should display rows with all the columns.
Any Help?
This should get you started:
DECLARE #TABLE TABLE (SuppID INT, AreaID INT, SuppNo VARCHAR(5), SupName VARCHAR(5), SupPrice INT)
INSERT INTO #TABLE
SELECT 1,3,'526','ANC',100 UNION
SELECT 1,3,'985','JTT',200 UNION
SELECT 3,4,'100','HIK',300
-- select data before updates
SELECT * FROM #TABLE
-- add a row count by AreaID/SuppID
;WITH T1 AS
(
SELECT *
,SUM(1) OVER(PARTITION BY AREAID,SUPPID) AS ROWCNT
FROM #TABLE
)
-- set the SuppNo blank on rows that have more than 1 match
UPDATE T1 SET SuppNo='' WHERE ROWCNT>1
-- add a row # by AreaID/SuppID
;WITH T2 AS
(
SELECT *
,ROW_NUMBER() OVER(PARTITION BY AREAID,SUPPID ORDER BY AREAID,SUPPID) AS ROWID
FROM #TABLE
)
-- delete duplicate rows
DELETE
FROM T2
WHERE ROWID>1
-- select data after updates
SELECT * FROM #TABLE