Get max date based on another column in SQL - sql

I have a table variable which consists of columns id, date and status as shown below
DECLARE #DateValues TABLE (
id int identity(1,1),
dates datetime,
status varchar (5)
)
And follows is the sample data
INSERT INTO #DateValues values ('5/22/2021','')
INSERT INTO #DateValues values ('5/21/2021','ABC')
INSERT INTO #DateValues values ('5/22/2021','ABC')
Also declared a variable as shown below.
DECLARE #MaxID INT
From this table I need to get the row which containing the maximum value of date( MAX(dates) ) where status is 'ABC', from the above sample values, I should get the 3rd row as the result and I need to assign the corresponding id value of the row id to a variable (#MaxID).
I tried following queries but getting multiple result set
SELECT id, MAX(dates), Footer
FROM #DateValues
WHERE STATUS = 'ABC'
GROUP BY id, STATUS
SELECT id, dates, status
FROM #DateValues
WHERE dates = (
SELECT MAX(dates)
FROM #DateValues
);
I need something like:
#MaxID = id
FROM #DateValues
WHERE dates = (
SELECT MAX(dates)
FROM #DateValues
WHERE STATUS='ABC'
);
Please help.

Is this what you want?
SELECT *
FROM (
SELECT *, RN = ROW_NUMBER() OVER (ORDER BY dates DESC)
FROM #DateValues
WHERE status = 'ABC'
) AS D
WHERE D.RN = 1

Related

How to get the Values of recently inserted columns from Temporary Table?

I am not able to use the recently inserted Quantity value of #ACCT table in the Select statement to be used like
ser.ServiceRate * Quantity
Every time I get the ERROR
Cannot insert the value NULL into column 'Amount'
I am just a beginner so any pointers to solve this would help.
DECLARE #MinReservationId INT = (SELECT MIN(f.ReservationId) FROM dbo.Reservation AS f)
DECLARE #MaxReservationId INT = (SELECT MAX(f.ReservationId) FROM dbo.Reservation AS f)
DECLARE #QuantityNew INT
WHILE #MinReservationId <= #MaxReservationId
BEGIN
CREATE TABLE #Acct
(
ServiceId INT,
Quantity INT --> I WANT THIS VALUE TO BE USED BELOW
)
INSERT INTO dbo.[Transaction]
(
ReservationId,
ServiceId,
Rate,
Quantity,
Amount
)
OUTPUT inserted.ServiceId,Inserted.Quantity
INTO #Acct
(
ServiceId,
Quantity
)
SELECT
#MinReservationId,
ser.ServiceId,
ser.ServiceRate,
ABS(CHECKSUM(NEWID())%3) + 1,
ser.ServiceRate * (SELECT acc.Quantity from #Acct as acc) -> QUANTITY from #ACCT should be used here
FROM dbo.[Service] AS ser
SELECT #MinReservationId=#MinReservationId+1
Drop table #Acct
END
You can use a CTE in order to capture the NEWID() value created for every record of table dbo.[Service]. Then use this CTE to do the INSERT:
;WITH ToInsert AS
(
SELECT ServiceId ,
ServiceRate,
ABS(CHECKSUM(NEWID())%3) + 1 AS Quantity
FROM dbo.[Service]
)
INSERT INTO dbo.[Transaction]
(
ReservationId,
ServiceId,
Rate,
Quantity,
Amount
)
SELECT #MinReservationId,
ServiceId,
ServiceRate,
Quantity,
ServiceRate * Quantity
FROM ToInsert

An aggregate may not appear in the set list of an UPDATE statement T-SQL

In T-SQL I'm attempting to update a stock user field with the number of weeks we expect it to be delivered to us by taking the difference between today and the purchase order due in dates. However the select query can return more than one line of purchase orders if there is more than one purchase order containing that product (obviously). I would like to take the smallest number it returns / minimum value but obviously cannot do this within the update query. Can anyone recommend a workaround? Thanks.
UPDATE [Exchequer].[ASAP01].[STOCK]
SET stUserField7 = DATEDIFF(day,CONVERT(VARCHAR(8), GETDATE(), 112),min(tlLineDate)) / 7 + 1
FROM [Exchequer].[ASAP01].[STOCK]
JOIN [Exchequer].[ASAP01].[CUSTSUPP]
ON stSupplier = acCode
JOIN [Exchequer].[ASAP01].[DETAILS]
ON stCode = tlStockCodeTrans1
WHERE stSupplier <> '' AND stQtyOnOrder > '0' AND stQtyOnOrder > stQtyAllocated
AND tlOurRef like 'POR%' AND (floor(tlQtyDel) + floor(tlQtyWOFF)) < floor(tlQty)
AND tlLineDate >= CONVERT(VARCHAR(8),GETDATE(), 112)
Why are you casting date to varchar for the difference?
This is not date but how you can use a window function in an update
declare #maps table(name varchar(10), isUsed bit, code varchar(10));
insert into #Maps values
('NY', 1, 'NY1')
, ('NY', 0, 'NY2')
, ('FL', 0, 'FL1')
, ('TX', 0, 'TX1')
declare #Results table (id int identity primary key, Name varchar(20), Value int, Code varchar(20), cnt int)
insert into #results values
('FL', 12, 'FL1', null)
, ('TX', 54, 'TX1', null)
, ('TX', 56, 'TX1', null)
, ('CA', 50, 'CA1', null)
, ('NJ', 40, 'NJ1', null)
select * from #results
order by name, Value desc
update r
set r.cnt = tt.cnt
from #results r
join ( select id, max(value) over (partition by name) as cnt
from #Results
) tt
on r.id = tt.id
select * from #results
order by name, value desc
Build a SELECT query with columns for the following:
The primary key of the [Exchequer].[ASAP01].[STOCK] table
The new desired stUserField7
Given the MIN(tlLineDate) expression in the original question, if this SELECT query does not have either a GROUP BY clause or change to use an APPLY instead of a JOIN, you've probably done something wrong.
Once you have that query, use it in an UPDATE statement like this:
UPDATE s
SET s.stUserField7 = t.NewValueFromSelectQuery
FROM [Exchequer].[ASAP01].[STOCK] s
INNER JOIN (
--- your new SELECT query here
) t ON t.<primary key field(s)> = s.<primary key field(s)>

Find missing numbers with SQL

In a large log file I have records containing the field INVNO (invoice-number).
The lowest and highest values are easy to find, BUT it looks like some numbers in between are not there.
Anyone got a trick with SQL, which can tell which numbers are missing within the number range?
use the following table valued function that takes 2 parameters : the min and max numbers,
and returns a list of missing number,
suppose your table name is YOUR_TABLE and the column name called InvNo
create FUNCTION [dbo].[MissingInvoiceNumbers]
(
#minPaym bigint,
#MaxPaym bigint
)
RETURNS #tmp table(numbers bigint)
AS
BEGIN
declare #n bigint --#minPaym bigint , #MaxPaym bigint,
declare #tmpAll table(Allnumbers bigint)
set #n= #minPaym
delete #tmp
delete #tmpAll
while (#n<=#MaxPaym)
begin
INSERT INTO #tmpAll
(AllNUMBERS)
VALUES (#n)
set #n=#n+1
end
INSERT INTO #tmp
(numbers)
SELECT Allnumbers
FROM #tmpAll
where Allnumbers not in (select distinct convert(bigint,InvNo) as InvoiceNum from YOUR_TABLE where
InvNo <> '' )
return
END
For oracle this should work. For any other database you just need to change way to generate the number sequence.
with vals as (
select rownum r
from dual
connect by rownum between {min} and {max}
)
select *
from vals v
left join {sometable} s on s.{someid} = v.r
where s.{someid} is null
The trick is just to generate numbers between min and max value, join table with invoices to this generated sequence and filter out everything that match.
Just join the table on itself...
DECLARE #tvp TABLE ( INVNO INT )
INSERT INTO #tvp
VALUES ( 1 ),
( 2 ),
( 3 ),
( 5 ),
( 6 ),
( 7 ),
( 8 ),
( 9 ),
( 10 ),
( 11 )
SELECT *
FROM #tvp;
SELECT t.INVNO + 1
FROM #tvp t
LEFT OUTER JOIN #tvp x ON x.INVNO = t.INVNO + 1
WHERE ISNULL(x.INVNO, 0) = 0;

How can I order data and add a record to the first position of the data set?

I know I can create a temp table, insert records, order it and then use union afterwards, but I'm looking for alternative routes. I tried a cte, but I had to order the entire thing which doesn't work as my unioned record doesn't stay "on top".
Basically, I have at able with Id INT, Name VARCHAR(MAX) fields and I want to ORDER BY Name before I add an entry at the row[0] position in the return set. If I order after the union, the row I wanted at row[0] gets ordered with it.
Any ideas?
You were on the right track with a union query. Force the sort with static values.
select 0 sortfield, '' name, etc
union
select 1 sortfield, name, etc
from etc
order by sortfield, name.
CREATE TABLE #temp (
idnt INT IDENTITY(2) NOT NULL --This begins the identity col with a value of 2
,Id INT
,Name VARCHAR(MAX)
)
INSERT INTO #temp
SELECT
...
FROM myTable
ORDER BY Name
CREATE TABLE #tempAPPEND (
idnt INT IDENTITY(1) NOT NULL --This begins the identity col with a value of 1
,Id INT
,Name VARCHAR(MAX)
)
INSERT INTO #tempAPPEND (Id, Name)
VALUES ('34384','Pinal Dave') -- SAMPLE VALUES
SELECT * FROM #temp
UNION
SELECT * FROM #tempAPPEND
ORDER BY idnt

Create unique ID based on grouped UserId

trying to write some SQL that does the following.
If I have a user id field, 12345, and there are 10 records for that user, I want to make a field that goes 1234xxxx
where xxxx refers to order of those records, based on a date field, 1 - 10
so 12340001, 12340002, 12340003 etc, up to 12340010
Thoughts?
Here is a method for getting the new value, assuming the userid is a string
select (left(userid, 4)+right(100000 +
row_number() over (partition by userid order by datefield), 4)
)
You can also use this in an update statement, if you want to change the value in the table.
Declare #x Table (Id INT)
INSERT INTO #x (ID) VALUES (1001),(1002),(1003),(1004),(1005)
select * from #x
select (
left(ID, 4)+right(10000 +DENSE_RANK() over ( order by Id), 4)
)
from #x
we can also use dense rank to get desired output