using both cte and variables to update dates in SQL - tsql

I'm currently trying to implement a bit of code that will take the dates for a given list of 160ish rows and update them to be one minute after another date from the same table.
so for example from these would go from:
> 1058841 2018-06-20 14:15:04.000 Copy of NtO produced
> 1058841 2018-06-14 19:58:03.000 NTO service date set to 24/05/2018
> 969565 2018-06-20 14:15:01.000 17530 Copy of NtO produced
> 969565 2018-06-14 19:58:03.000 148 NTO service date set to 24/05/2018
to this:
> 1058841 2018-06-14 19:59:03.000 Copy of NtO produced
> 1058841 2018-06-14 19:58:03.000 NTO service date set to 24/05/2018
> 969565 2018-06-14 19:59:03.000 17530 Copy of NtO produced
> 969565 2018-06-14 19:58:03.000 148 NTO service date set to 24/05/2018
the code I have so far:
declare #thisdate datetime
set #thisdate = (
select * from (
select row_number() over (partition by te_system_ref order by (select 0)) as rownumber, te_date, te_system_ref, te_event from ticket_events where te_system_ref in
(select sl_system_ref from statutory_letter where sl_letter_batch = 9429)and te_event = 'Copy of NtO produced'
) t
where rownumber = 1
);
with rn as
( select * from (
select row_number() over (partition by te_system_ref order by (select 0)) as rownumber1, te_date, te_system_ref, te_event from ticket_events where te_system_ref in
(
select sl_system_ref from statutory_letter where sl_letter_batch = 9429
)
and te_event = 'Copy of NtO produced'
) t where rownumber1 = 1)
select * from rn where te_date between dateadd(hour,1,#thisdate) and dateadd(hour,-1,#thisdate)
this currently gives me the error:
Msg 116, Level 16, State 1, Line 9 Only one expression can be
specified in the select list when the subquery is not introduced with
EXISTS.
If anyone could please explain where i'm going wrong, or point me in the right direction it would be massively appreciated

set #thisdate = (
select * from (
select row_number() over (partition by te_system_ref order by (select 0)) as rownumber, te_date, te_system_ref, te_event from ticket_events where te_system_ref in
(select sl_system_ref from statutory_letter where sl_letter_batch = 9429)and te_event = 'Copy of NtO produced'
) t
where rownumber = 1
);
Here you try to assign several values to a scalar variable.
I guess you actually want te_date.
set #thisdate = (
select te_date from (
select row_number() over (partition by te_system_ref order by (select 0)) as rownumber, te_date from ticket_events where te_system_ref in
(select sl_system_ref from statutory_letter where sl_letter_batch = 9429)and te_event = 'Copy of NtO produced'
) t
where rownumber = 1
);

Related

SQL Server - Select with Group By together Raw_Number

I'm using SQL Server 2000 (80). So, it's not possible to use the LAG function.
I have a code a data set with four columns:
Purchase_Date
Facility_no
Seller_id
Sale_id
I need to identify missing Sale_ids. So every sale_id is a 100% sequential, so the should not be any gaps in order.
This code works for a specific date and store if specified. But i need to work on entire data set looping looping through every facility_id and every seller_id for ever purchase_date
declare #MAXCOUNT int
set #MAXCOUNT =
(
select MAX(Sale_Id)
from #table
where
Facility_no in (124) and
Purchase_date = '2/7/2020'
and Seller_id = 1
)
;WITH TRX_COUNT AS
(
SELECT 1 AS Number
union all
select Number + 1 from TRX_COUNT
where Number < #MAXCOUNT
)
select * from TRX_COUNT
where
Number NOT IN
(
select Sale_Id
from #table
where
Facility_no in (124)
and Purchase_Date = '2/7/2020'
and seller_id = 1
)
order by Number
OPTION (maxrecursion 0)
My Dataset
This column:
case when
Sale_Id=0 or 1=Sale_Id-LAG(Sale_Id) over (partition by Facility_no, Purchase_Date, Seller_id)
then 'OK' else 'Previous Missing' end
will tell you which Seller_Ids have some sale missing. If you want to go a step further and have exactly your desired output, then filter out and distinct the 'Previous Missing' ones, and join with a tally table on not exists.
Edit: OP mentions in comments they can't use LAG(). My suggestion, then, would be:
Make a temp table that that has the max(sale_id) group by facility/seller_id
Then you can get your missing results by this pseudocode query:
Select ...
from temptable t
inner join tally N on t.maxsale <=N.num
where not exists( select ... from sourcetable s where s.facility=t.facility and s.seller=t.seller and s.sale=N.num)
> because the only way to "construct" nonexisting combinations is to construct them all and just remove the existing ones.
This one worked out
; WITH cte_Rn AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY Facility_no, Purchase_Date, Seller_id ORDER BY Purchase_Date) AS [Rn_Num]
FROM (
SELECT
Facility_no,
Purchase_Date,
Seller_id,
Sale_id
FROM MyTable WITH (NOLOCK)
) a
)
, cte_Rn_0 as (
SELECT
Facility_no,
Purchase_Date,
Seller_id,
Sale_id,
-- [Rn_Num] AS 'Skipped Sale'
-- , case when Sale_id = 0 Then [Rn_Num] - 1 Else [Rn_Num] End AS 'Skipped Sale for 0'
, [Rn_Num] - 1 AS 'Skipped Sale for 0'
FROM cte_Rn a
)
SELECT
Facility_no,
Purchase_Date,
Seller_id,
Sale_id,
-- [Skipped Sale],
[Skipped Sale for 0]
FROM cte_Rn_0 a
WHERE NOT EXISTS
(
select * from cte_Rn_0 b
where b.Sale_id = a.[Skipped Sale for 0]
and a.Facility_no = b.Facility_no
and a.Purchase_Date = b.Purchase_Date
and a.Seller_id = b.Seller_id
)
--ORDER BY Purchase_Date ASC

tsql - Group By on computed columns

Please advice on a better way to do this.
I am sure this can be done in one query itself.
declare #tempTale table (ID bigint, ArticleDate datetime,CommentDate
datetime,MostRecentDate datetime)
declare #MinDate datetime;
set #MinDate = getdate();
set #MinDate = DATEADD(YEAR,-100,#MinDate)
insert into #tempTale
select USER_ARTICLEID, User_Article.CREATED_ON, coalesce(comment.CREATED_ON,#MinDate),
case when coalesce(User_Article.CREATED_ON,#MinDate) > coalesce(comment.CREATED_ON,#MinDate) then User_Article.CREATED_ON else comment.CREATED_ON end as MostRecentDate
from User_Article left join Comment on Comment.CONTENTID = User_Article.USER_ARTICLEID and comment.CONTENT_TYPE = User_Article.CONTENT_TYPE
order by MostRecentDate desc
select distinct top 10 ID,MAX(MostRecentDate) from #tempTale group by ID
order by MAX(MostRecentDate) desc
obvious change is to use sub-queries:
select distinct top 10 ID, MAX(MostRecentDate) from
(
select
USER_ARTICLEID as ID,
(case
when coalesce(User_Article.CREATED_ON,#MinDate) > coalesce(comment.CREATED_ON,#MinDate) then User_Article.CREATED_ON
else comment.CREATED_ON end) as MostRecentDate
from User_Article
left join Comment
on Comment.CONTENTID = User_Article.USER_ARTICLEID and comment.CONTENT_TYPE = User_Article.CONTENT_TYPE
)
group by ID
order by 2 desc
but you don't group on computed columns, so you can go with simple one:
select distinct top 10
USER_ARTICLEID as ID,
(case
when coalesce(User_Article.CREATED_ON,#MinDate) > coalesce(comment.CREATED_ON,#MinDate) then User_Article.CREATED_ON
else comment.CREATED_ON end) as MostRecentDate
from User_Article
left join Comment
on Comment.CONTENTID = User_Article.USER_ARTICLEID and comment.CONTENT_TYPE = User_Article.CONTENT_TYPE
group by USER_ARTICLEID
order by 2 desc

Is T-SQL (2005) RANK OVER(PARTITION BY) the answer?

I have a stored procedure that does paging for the front end and is working fine. I now need to modify that procedure to group by four columns of the 20 returned and then only return the row within each group that contains the lowest priority. So when resort_id, bedrooms, kitchen and checkin (date) all match then only return the row that has the min priority. I have to still maintain the paging functionality. The #startIndex and #upperbound are parms passed into the procedure from the front end for paging. I’m thinking that RANK OVER (PARTITION BY) is the answer I just can’t quite figure out how to put it all together.
SELECT I.id,
I.resort_id,
I.[bedrooms],
I.[kitchen],
I.[checkin],
I.[priority],
I.col_1,
I.col_2 /* ..... (more cols) */
FROM (
SELECT ROW_NUMBER() OVER(ORDER by checkin) AS rowNumber,
*
FROM Inventory
) AS I
WHERE rowNumber >= #startIndex
AND rowNumber < #upperBound
ORDER BY rowNumber
Example 2 after fix:
SELECT I.resort_id,
I.[bedrooms],
I.[kitchen],
I.[checkin],
I.[priority],
I.col_1,
I.col_2 /* ..... (more cols) */
FROM Inventory i
JOIN
(
SELECT ROW_NUMBER() OVER(ORDER BY h.checkin) as rowNumber, MIN(h.id) as id
FROM Inventory h
JOIN (
SELECT resort_id, bedrooms, kitchen, checkin, id, MIN(priority) as priority
FROM Inventory
GROUP BY resort_id, bedrooms, kitchen, checkin, id
) h2 on h.resort_id = h2.resort_id and
h.bedrooms = h2.bedrooms and
h.kitchen = h2.kitchen and
h.checkin = h2.checkin and
h.priority = h2.priority
GROUP BY h.resort_id, h.bedrooms, h.kitchen, h.checkin, h.priority
) AS I2
on i.id = i2.id
WHERE rowNumber >= #startIndex
AND rowNumber < #upperBound
ORDER BY rowNumber
I would accompish it this way.
SELECT I.resort_id,
I.[bedrooms],
I.[kitchen],
I.[checkin],
I.[priority],
I.col_1,
I.col_2 /* ..... (more cols) */
FROM Inventory i
JOIN
(
SELECT ROW_NUMBER(ORDER BY Checkin) as rowNumber, MIN(id) id
FROM Inventory h
JOIN (
SELECT resort_id, bedrooms, kitchen, checkin id, MIN(priority) as priority
FROM Inventory
GROUP BY resort_id, bedrooms, kitchen, checkin
) h2 on h.resort_id = h2.resort and
h.bedrooms = h2.bedrooms and
h.kitchen = h2.kitchen and
h.checkin = h2.checkin and
h.priority = h2.priority
GROUP BY h.resort_id, h.bedrooms, h.kitchen, h.checkin, h.priority
) AS I2
on i.id = i2.id
WHERE rowNumber >= #startIndex
AND rowNumber < #upperBound
ORDER BY rowNumber

T-SQL: Simplify Select statement with ROW_NUMBER

I have the following select SQL that does a basic select statement although it does include a calculated column:
Select *
From
(
Select *,
ROW_NUMBER() OVER
(ORDER BY
CASE WHEN #sortBy = 0 THEN R.DateCreated End Desc,
CASE WHEN #sortBy = 1 THEN R.DateCreated end Asc,
CASE WHEN #sortBy = 2 THEN TotalVotes END Desc,
CASE WHEN #sortBy = 2 THEN R.TotalFoundNotUseful END Desc
) AS RowNumber
From
(
Select *, (TotalFoundUseful + TotalFoundNotUseful) As TotalVotes
From Reviews
Where (DealID = #dealID) And (TotalAbuses < 10) And (Deleted = 0)
) As R
) As Rev
Where RowNumber BETWEEN #startRecord AND #endRecord
If you look carefully, the SELECT statement itself is executed 3 times. I can't believe that this is necessary. Is there a way to reduce this to 2 select statements (or possibly even one). I don't actually need to return the RowNumber. It is only used for selecting rows within a certain range.
You can do it with two by putting the rownumber in with the original select against reviews. You can't go to one if you want to have a WHERE clause on a windowing function like ROW_NUMBER.
You do have to write TotalFoundUseful + TotalFoundNotUseful twice but it will only be evaluated once so that doesn't effect performance.
I also wouldn't expect moving to two to have any effect on performance but you should test it.
Select *
From
(
Select *, (TotalFoundUseful + TotalFoundNotUseful) As TotalVotes,
ROW_NUMBER() OVER
(ORDER BY
CASE WHEN #sortBy = 0 THEN DateCreated End Desc,
CASE WHEN #sortBy = 1 THEN DateCreated end Asc,
CASE WHEN #sortBy = 2 THEN TotalFoundUseful + TotalFoundNotUseful END Desc,
CASE WHEN #sortBy = 2 THEN TotalFoundUseful END Desc
) AS RowNumber
From Reviews
Where (DealID = #dealID) And (TotalAbuses < 10) And (Deleted = 0)
) As Rev
Where RowNumber BETWEEN #startRecord AND #endRecord

Need to retrieve n-rows that are not at the beginning or in the end of the selected list

I have written sql statement :
select * from (
select count(*) as NumberofSignals,signals.transmitter_account,signals.class,signals.type,signals.signal_mode,
signals.area_id,signals.sector_id,signals.region_info_id,signals.zone_info_id,signals.user_id,signals.device_id,
signals.panel_name,signals.panel_id,signals.sector_name,signals.region_code,signals.area_name,signals.zone_code,
signals.description,signals.transmitter_name,signals.transmitter_id,signals.color,'event' as Event,get_name(signals.id,'event') as event_value,
'packetnumber' as packetnumber,get_name(signals.id,'packetnumber') as packetnumber_value,wm_concat(distinct get_name(signals.id,'repeater')) as repeater,
round(avg(get_name(signals.id,'signallevel'))) as avg_signallevel,min(to_char(signals.signal_forming_time, 'yyyy/mm/dd hh24:mi:ss')) as formingtime,
get_name(signals.id,'address') as address,get_name(signals.id,'username') as username,get_name(signals.id,'chaneltype') as channeltype,
get_name(signals.id,'code') as code,get_name(signals.id,'account') as account
from signals,signal_custom_fields where signals.id = signal_custom_fields.signal_id and
signals.id in (select id from (select id,rownum num from((select signals.id
from signals,signal_custom_fields where signal_custom_fields.field_name = 'event'
and signal_custom_fields.field_value is not null and signals.id = signal_custom_fields.signal_id
and signals.signal_forming_time >= to_date('2011/5/10 14:34:44', 'yyyy/mm/dd hh24:mi:ss')
AND signals.signal_forming_time <= to_date('2011/5/10 15:34:44', 'yyyy/mm/dd hh24:mi:ss'))
intersect (select distinct signals.id from signals,signal_custom_fields
where signal_custom_fields.field_name = 'packetnumber' and signal_custom_fields.field_value is not null
and signals.id = signal_custom_fields.signal_id
and signals.signal_forming_time >= to_date('2011/5/10 14:34:44', 'yyyy/mm/dd hh24:mi:ss')
AND signals.signal_forming_time <= to_date('2011/5/10 15:34:44', 'yyyy/mm/dd hh24:mi:ss')))
order by id desc)) group by 'event',signals.transmitter_account,signals.class,
signals.type,signals.signal_mode,signals.area_id,signals.sector_id,signals.region_info_id,signals.zone_info_id,
signals.user_id,signals.device_id,signals.panel_name,signals.panel_id,signals.sector_name,signals.region_code,
signals.area_name,signals.zone_code,signals.description,signals.transmitter_name,signals.transmitter_id,
signals.color, get_name(signals.id,'event'), 'packetnumber',get_name(signals.id,'username'),
get_name(signals.id,'chaneltype'),
get_name(signals.id,'code'),
get_name(signals.id,'account'), get_name(signals.id,'packetnumber'),get_name(signals.id,'address'),
TO_CHAR(signals.signal_forming_time ,'dd/mm/yyyy hh24'),
TRUNC(to_number(to_char(signals.signal_forming_time ,'mi'))/(30))
order by event)where rownum < 300
and here i get the first 300 rows, but how i need to rewright this statment to retrieve second 300 rows ???
Your query doesn't have the rownum listed in the first nested table. Add a rownum column in the first nested table then you can do a between function in the where clause at the top level:
--create a demo table
DROP TABLE paging_test;
CREATE TABLE paging_test AS
(SELECT rownum x FROM user_tables
);
--count how many records exist (in my case there is 821)
SELECT COUNT(*)
FROM paging_test;
--get the first 300 rows
SELECT *
FROM
(SELECT rownum rn, x FROM paging_test ORDER BY x
) pt
WHERE pt.rn BETWEEN 1 AND 300 ;
--get the next 300 rows
SELECT *
FROM
(SELECT rownum rn, x FROM paging_test ORDER BY x
) pt
WHERE pt.rn BETWEEN 300 AND 600 ;
You might also be interested in my reference:
References:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:948366252775