Subquery - Incorrect Syntax near the keyword 'declare' - sql

Having an issue debugging this, hoping someone can help me clear this up. This is part of a much longer query, but the subquery "B" is the only part that is causing a problem, not sure why... I'm obviously missing something. I'm using sql-server.
The sub query runs fine on its own, just not with the rest of the query.
DECLARE #dstrt AS DATETIME
SET #dstrt = '2020-09-01 00:00:00'
DECLARE #dend AS DATETIME
SET #dend = '2020-09-30 23:59:59'
DECLARE #UnpaidChgsTot table
(
SiteID INT,
Period nvarchar(30),
dcDlqntTot money,
iDelUnits int,
dcPctUnits money,
dcPctGrossPot money,
dcPctActOcc money,
iDatePeriod int
)
DECLARE #sLanguageTermColName nvarchar(20)
SET #sLanguageTermColName = 'English'
-- DECLARE some period counters
DECLARE #StartDayNumber int
DECLARE #EndDayNumber int
SET #StartDayNumber = 0
SET #EndDayNumber = -1
--Hold the original date value
DECLARE #dEndORig datetime
SET #dEndORig = #dEnd
DECLARE #dcGrossPotDenom money
DECLARE #dcActOccDenom money
DECLARE #iTotUnitsDenom int
SET #dcGrossPotDenom = 1
SET #dcActOccDenom = 1
SET #iTotUnitsDenom = 1
--Define a holding table for charge balances by ChargeID
DECLARE #BalT table
(
SiteID int,
ChargeID int,
LedgerID int,
ChargeDescID int,
sChgCategory nvarchar(20),
sDefAcctCode nvarchar(20),
dChgStrt datetime,
dcBalAmt money,
dcBalTax1 money,
dcBalTax2 money
)
/*
* Updated. Delete was taking too long to run, added to WHERE to get rid
* Date: 10192009
* Josh
*/
--Fill the #BalT with charge balances for charges <=dEND
INSERT INTO #BalT
SELECT
B.SiteID,
B.ChargeID,
B.LedgerID,
B.ChargeDescID,
CD.sChgCategory,
CA.sDefAcctCode,
B.dChgStrt,
dcAmt,
dcTax1,
dcTax2
FROM -- PROBLEM STARTS HERE
(
DECLARE #ChargesT2 table
(
SiteID int,
ChargeID int,
ChargeDescID int,
sChgCategory nvarchar(50),
sDefAcctCode nvarchar(5),
dChgStrt datetime,
LedgerID int,
dcAmt money,
dcTax1 money,
dcTax2 money,
sChargeTag nvarchar(20)
)
DECLARE #fnPmtSumByChargeT Table
(
SiteID INT,
ChargeID int,
dcPmtSum money
)
DECLARE #fnPmtSumByChargeT2 Table
(
SiteID INT,
ChargeID int,
dcPmtSum money
)
DECLARE #ChargesTempT table
(
SiteID INT,
ChargeID int,
dcAmt money,
dcTax1 money,
dcTax2 money
)
Declare #ChargesT table
(
SiteID INT,
ChargeID int,
ChargeDescID int,
sChgCategory nvarchar(50),
sDefAcctCode nvarchar(5),
dChgStrt datetime,
LedgerID int,
dcAmt money,
dcTax1 money,
dcTax2 money,
sChargeTag nvarchar(20)
)
INSERT INTO #ChargesT2
SELECT
C.SiteID,
C.ChargeID,
C.ChargeDescID,
sChgCategory,
sDefAcctCode,
C.dChgStrt,
C.LedgerID,
Coalesce(C.dcAmt,0.0) AS dcBalAmt,
Coalesce(C.dcTax1,0.0) AS dcBalTax1,
Coalesce(C.dcTax2,0.0) AS dcBalTax2,
CASE
WHEN CAST(CA.sDefAcctCode AS INT) = 4000 THEN N'Rent'
WHEN CAST(CA.sDefAcctCode AS INT) = 4042 THEN N'LateFee'
WHEN CAST(CA.sDefAcctCode AS INT) = 4041 THEN N'AdminFee'
WHEN CAST(CA.sDefAcctCode AS INT) = 4070 THEN N'Insurance'
WHEN CAST(CA.sDefAcctCode AS INT) BETWEEN 4060 AND 4068 OR CAST(CA.sDefAcctCode AS INT) BETWEEN 4071 AND 4079 THEN N'POS'
--WHEN CAST(CA.sDefAcctCode AS INT) = 2020 THEN 'SecDep'
ELSE N'Others'
END as sChargeTag
FROM Charges AS C
INNER JOIN ChargeDesc AS CD ON C.ChargeDescID = CD.ChargeDescID
LEFT OUTER JOIN ChartOfAccts AS CA ON CD.ChartofAcctID = CA.ChartOfAcctID
WHERE
C.dDeleted IS NULL
AND C.dChgStrt <= #dend
--2016-01-12 - Case # 237424 - C158, L005, Unit 10478, Tenant - Zach Reese.
--Commented out dCreated evaluation. This is because A/R does not prevent backdating charges from changing historical reports. There is no way these two reports
--can tie out in the same period if we do not allow backdating charges that we created in a future period. Ex. Late fee created on January 2, 2016, but dChgStrt of 12/29/2015.
--AND dCreated <= #dEnd --This is to catch a case where NSF charges were added (backdated) after the report end date, affecting historical reporting. 02102011 Josh
AND (bNSF = 0 OR (bNSF = 1 AND dCreated <= #dend))--updated the logic to be different for NSF charges to not change reports historically; this loigc is consistant with A/R. Case # 269909
GROUP BY C.siteID, C.ChargeID, C.ChargeDescID, sChgCategory, sDefAcctCode, C.dChgStrt, C.LedgerID, C.dcAmt, C.dcTax1, C.dcTax2, CA.sDefAcctCode
INSERT INTO #fnPmtSumByChargeT2
SELECT
SiteID,
ChargeID,
dcPmtSum
FROM
(
SELECT
pay.SiteID,
Pay.ChargeID,
SUM(pay.dcPmtAmt) AS dcPmtSum
FROM
(
SELECT
SiteID,
ChargeID,
dcPmtAmt
FROM Payments
WHERE
(dDeleted Is Null)
--AND (bNSF = 0) --this fn must return ALL payments to calculate balances correctly
AND (dPmt <= #dend)
) AS Pay
GROUP BY SiteID, ChargeID
) AS P
INSERT INTO #fnPmtSumByChargeT2
SELECT
C.SiteID,
C.ChargeID,
0
FROM #ChargesT2 C
INSERT INTO #fnPmtSumByChargeT
SELECT
P.SiteID,
P.ChargeID,
SUM(P.dcPmtSum)
FROM #fnPmtSumByChargeT2 P
GROUP BY P.SiteID, P.ChargeID
INSERT INTO #ChargesTempT
SELECT
P.SiteID,
P.ChargeID,
C.dcAmt - Coalesce(dbo.fnPartNonTax(C.dcAmt, C.dcTax1, C.dcTax2, P.dcPmtSum, 2),0.0),
C.dcTax1 - Coalesce(dbo.fnPartTax1(C.dcAmt, C.dcTax1, C.dcTax2, P.dcPmtSum, 2,2),0.0),
C.dcTax2 - Coalesce(dbo.fnPartTax2(C.dcAmt, C.dcTax1, C.dcTax2, P.dcPmtSum,2,2),0.0)
FROM #ChargesT2 C
INNER JOIN #fnPmtSumByChargeT P ON C.ChargeID = P.ChargeID
GROUP BY P.SiteId, P.ChargeID, C.dcAmt, dcTax1, dcTax2, dcPmtSum
HAVING (dcAmt + dcTax1 + dcTax2 - dcPmtSum) > 0 -- Removed 0 sum columns: This was a major bottleneck for this function 10202009 J
INSERT INTO #ChargesT
SELECT
C.SiteID,
C.ChargeID,
C.ChargeDescID,
C.sChgCategory,
C.sDefAcctCode,
C.dChgStrt,
C.LedgerID,
CT.dcAmt,
CT.dcTax1,
CT.dcTax2,
C.sChargeTag
FROM #ChargesT2 C
INNER JOIN #ChargesTempT CT ON C.ChargeID = CT.ChargeID
SELECT *
FROM #ChargesT
AS ChargeT
) AS B -- PROBLEM ENDS HERE
INNER JOIN ChargeDesc AS CD ON B.ChargeDescID = CD.ChargeDescID AND B.Siteid = CD.SiteID
I indicated "Problem starts here" and "problem ends here" in the notes, if that helps.
Thanks in advance.

Inside a subquery the only thing you is write a select statement. You cannot write anything you want like it is a code block.
In your case, you may accomplish what you want by moving all those table variables to outside the parentheses and populating them, then inside the parentheses you just do the select. Like I said, it is not a code block, there are no local variables. There's no prettier way. SQL is a simple language for querying information. That's just how it is.
Alternatively, you may like to use Common Table Expressions (CTEs) to give each subquery a name. The subqueries do not exist as any temp variable or table, just as helper names available during the main query. That may solve what you want do to.

Related

Use variable parameter in Execute SQL Task multiple times SSIS

hey guys so i created two variables: startdate and todate and I am attempting to pass them through my SQL query in SSIS and I have added them in my Parameter Mapping but how does SSIS which variable to use after if it sees a third question mark?
for example: so how would SSIS know to use startdate when it inserts into #multileg and not use the todate variable?
e
--Declare #StartDate date
--declare #ToDate date
--set #startdate = dateadd(dd,-10, cast(getdate() as date))
--set #ToDate = dateadd(dd,-9,cast(getdate() as date))
---SSR Table with passenger info, both APAY and PET
create table #SSRData
([ssrfl] int, [ssrcode] char(4), [ssrsequenceid] smallint, [ssrstatuscode]
char(2), [servicestartcitycode] varchar(5),
[ssrstartdate] date, [databasetimestamp] datetime, [pnrlocator] char(8),
[pnrcreatedate] date, [passengersequenceid] smallint,
[namefirst] varchar(250), [namelast] varchar(250), [frequenttravelernumber]
varchar(25)
)
insert into #ssrdata
select distinct ssrfl,
s.ssrcode,s.ssrsequenceid,s.ssrstatuscode,s.servicestartcitycode,
s.ssrstartdate, s.databasetimestamp, s.pnrlocator, s.pnrcreatedate
,s.passengersequenceid, namefirst, namelast,frequenttravelernumber
--into #SSRData
from
(select cast(ssrflightnumber as int)ssrfl,
ssrcode,ssrsequenceid,ssrstatuscode,servicestartcitycode,
ssrstartdate, pnrlocator, pnrcreatedate
,passengersequenceid,databasetimestamp from dwjetblue2.dw.resssr
where SSRCode in ('APAY', 'PETC') and PNRLocator <>'purged'
and ssrstartdate >= ?
and ssrstartdate < ?)s
inner join dw.dw.ResPassenger p
on p.pnrcreatedate=s.pnrcreatedate
and p.pnrlocator=s.pnrlocator
and p.passengersequenceid=s.passengersequenceid
inner join dwjetblue2.dw.ResPassengerFT ft
on ft.pnrcreatedate=s.pnrcreatedate
and ft.pnrlocator=s.pnrlocator
and ft.passengersequenceid=s.passengersequenceid
--MultiLeg
create table #multi
(
[pnrlocator] char(8), [pnrcreatedate] date
,[segmentnumber] tinyint, [marketingflightnumber] char(5)
,[servicestartcity] char(3), [serviceendcity] char(3)
,[servicestartdate] date
)
insert into #multi
select distinct
pnrlocator p, pnrcreatedate d ,segmentnumber s,
marketingflightnumber fl,
servicestartcity sc, serviceendcity ec, servicestartdate sd
--into #multi
from dw2.dw.resflight
where servicestartdate >= ?
Brad's answer is a great way to do it. Another way is to simply add the parameter to your Parameter Mapping a second time.
A third way is to build your SQL statement in a variable with expressions. Then in your Execute SQL Task, your SQLSourceType would be Variable, and then you select the variable that contains your query. This can be an easy way to do it so you avoid messing around with picking the right data types for your parameters.
You wouldnt at the top of your code declare variables for the dates passed and set the values from the paramaters/? makrs to those and just use the variables in your code below
DECLARE #StartDate as Date
DECLARE #ToDate as DATE
SET #StartDate = ?
SET #ToDate = ?
-- so do it like this:
Select * from your table where MyDateColumn Between #StartDate and #ToDate
Then use those in your code below where you need them.
This lets you use the variables more than once and is cleaner and easier to see that your using parameters and how/where.
*** Updated to use your code:
DECLARE #StartDate as Date
DECLARE #ToDate as DATE
SET #StartDate = ?
SET #ToDate = ?
---SSR Table with passenger info, both APAY and PET
create table #SSRData
([ssrfl] int, [ssrcode] char(4), [ssrsequenceid] smallint, [ssrstatuscode]
char(2), [servicestartcitycode] varchar(5),
[ssrstartdate] date, [databasetimestamp] datetime, [pnrlocator] char(8),
[pnrcreatedate] date, [passengersequenceid] smallint,
[namefirst] varchar(250), [namelast] varchar(250), [frequenttravelernumber]
varchar(25)
)
insert into #ssrdata
select distinct ssrfl,
s.ssrcode,s.ssrsequenceid,s.ssrstatuscode,s.servicestartcitycode,
s.ssrstartdate, s.databasetimestamp, s.pnrlocator, s.pnrcreatedate
,s.passengersequenceid, namefirst, namelast,frequenttravelernumber
--into #SSRData
from
(select cast(ssrflightnumber as int)ssrfl,
ssrcode,ssrsequenceid,ssrstatuscode,servicestartcitycode,
ssrstartdate, pnrlocator, pnrcreatedate
,passengersequenceid,databasetimestamp from dwjetblue2.dw.resssr
where SSRCode in ('APAY', 'PETC') and PNRLocator <>'purged'
and ssrstartdate >= #StartDate --?
and ssrstartdate < #ToDate)s --?
inner join dw.dw.ResPassenger p
on p.pnrcreatedate=s.pnrcreatedate
and p.pnrlocator=s.pnrlocator
and p.passengersequenceid=s.passengersequenceid
inner join dwjetblue2.dw.ResPassengerFT ft
on ft.pnrcreatedate=s.pnrcreatedate
and ft.pnrlocator=s.pnrlocator
and ft.passengersequenceid=s.passengersequenceid
--MultiLeg
create table #multi
(
[pnrlocator] char(8), [pnrcreatedate] date
,[segmentnumber] tinyint, [marketingflightnumber] char(5)
,[servicestartcity] char(3), [serviceendcity] char(3)
,[servicestartdate] date
)
insert into #multi
select distinct
pnrlocator p, pnrcreatedate d ,segmentnumber s,
marketingflightnumber fl,
servicestartcity sc, serviceendcity ec, servicestartdate sd
--into #multi
from dw2.dw.resflight
where servicestartdate >= #StartDate

SQL Run query multiple times changing variable

I have a query which checks the status of a specific tank, however I have 50 tanks which I'd like to run this for (FV101, FV102, FV103 etc.)
I could union together 50 queries with the WHERE changed, but I suspect that there must be a better way.
The query is very simple:
DECLARE #tank varchar(5)
SET #tank = 'FV101'
SELECT
ROW_NUMBER() OVER (PARTITION BY [Item] ORDER BY [TankName]) [Row],
*
FROM
(
SELECT TOP 1
#tank [TankName],
T1.[Item],
CASE WHEN AVG(CAST(T0.[pHValue] AS dec (10,5))) NOT BETWEEN MAX(T2. [pH_lower]) AND MAX(T2.[pH_upper]) THEN 'Red' ELSE 'Black' END [Spec]
FROM
t005_pci_data T0 INNER JOIN t001_fvbatch T1 ON T1.[FVBatch] = T0. [FVBatch] LEFT JOIN t024_specifications T2 ON T2.[BeerBrand] = T1.[BeerBrand] AND [Type] = 'Finished Product'
WHERE
T0.[FVBatch] = (SELECT TOP 1 T0.[FVBatch] FROM t005_pci_data T0 INNER JOIN t001_fvbatch T1 ON T1.[FVBatch] = T0.[FVBatch] WHERE T1.[TankName] = 'FV101' ORDER BY T0.[DateTime] DESC) AND
EXISTS (SELECT [FVBatch] FROM t005_pci_data WHERE [TankName] = #tank AND [DateTime] >= DATEADD(day,-2,GETDATE()))
GROUP BY
T1.[Item],T0.[DateTime]
ORDER BY
T0.[DateTime] DESC
) a
Is there a way to pass a list of values to this query for it to use instead of repeating the query manually multiple times?
EDIT as per iamdave's suggestion
Schema (simplified) is as below:
The goal is to list everything which is currently in each tank and check if the value of the pH is within the acceptable limits.
Desired output (up to FV105) would be:
In this example there is nothing in tanks FV101 or FV104, as decided by the following code in the WHERE
EXISTS (SELECT [FVBatch] FROM t005_pci_data WHERE [TankName] = #tank AND [DateTime] >= DATEADD(day,-2,GETDATE()))
The end result is I would like to create a table in MSSRS which shows what item is in each tank and whether it is within specifications or not.
FURTHER EDIT with sample data as requested
(Not very imaginative I'm afraid)
declare #t1 table(FVBatch int, TankName nvarchar(5), Item nvarchar(20));
declare #t2 table(Item nvarchar(20), ph_lower decimal(10,2), ph_upper decimal(10,2));
declare #t3 table(FVBatch int, pHValue decimal(10,2), DateValue datetime);
insert into #t1 values
(3160001,'FV101','Stout')
,(3160002,'FV102','Stout')
,(3160003,'FV103','Stout')
,(3160004,'FV104','Pale Ale')
,(3160005,'FV105','Pale Ale')
,(3160070,'FST04','IPA');
insert into #t2 values
('Pale Ale',3.5,5.5)
,('Stout',2,3.5);
insert into #t3 values
(3160001,4 ,'20161209')
,(3160001,4 ,'20161210')
,(3160001,4 ,'20161212')
,(3160002,4 ,'20161218')
,(3160002,4 ,'20161220')
,(3160002,4 ,'20161222')
,(3160003,4 ,'20161218')
,(3160003,4 ,'20161220')
,(3160003,4 ,'20161222')
,(3160004,4 ,'20161209')
,(3160004,4 ,'20161210')
,(3160004,4 ,'20161212')
,(3160005,4 ,'20161218')
,(3160005,4 ,'20161220')
,(3160005,4 ,'20161222')
,(3160070,4.26,'20161218')
,(3160070,4.26,'20161216')
,(3160070,4.24,'20161215')
,(3160070,4.24,'20161214')
,(3160070,4.26,'20161213')
,(3160070,4.2 ,'20161212')
,(3160070,4.21,'20161211')
,(3160070,4.12,'20161209')
,(3160070,4.09,'20161208')
,(3160070,4.1 ,'20161207');
How does this do?
select row_number() over (partition by t1.Item order by t1.TankName) as RowNum
,t1.TankName
,t1.Item
,case when avg(t3.pHValue) between t2.ph_lower and t2.ph_upper
then 'Black'
else 'Red'
end as Spec
from #t1 t1
left join #t2 t2
on(t1.Item = t2.Item)
inner join(select FVBatch
,pHValue
,max(DateValue) as DateValue
from #t3
where DateValue >= cast(dateadd(d,-2,getdate()) as date)
group by FVBatch
,pHValue
) t3
on(t1.FVBatch = t3.FVBatch)
group by t1.TankName
,t1.Item
,t2.ph_lower
,t2.ph_upper
order by t1.TankName
,RowNum
Using your test data, the above query returns:
RowNum TankName Item Spec
1 FV102 Stout Red
2 FV103 Stout Red
1 FV105 Pale Ale Black
Edit based on conversation
/*
The full requirement is this:
there could be multiple of each measurement taken on any one date,
so I want to check that the average of these measurements per day is withing the range
each batch goes through several stages
if the stage isn't "bottle" or "can" then we look back 2 days
if it is one of those then we look back 5 days instead
*/
declare #t001_fvbatch table(FVBatch int
,TankName nvarchar(5)
,BeerBrand nvarchar(20)
);
declare #t024_specifications table(BeerBrand nvarchar(20)
,pH_lower decimal(10,2)
,pH_upper decimal(10,2)
,OG_lower decimal(10,2)
,OG_upper decimal(10,2)
,PG_lower decimal(10,2)
,PG_upper decimal(10,2)
,EBCHaze decimal(10,2)
,ABV_lower decimal(10,2)
,ABV_upper decimal(10,2)
,[Type] nvarchar(50)
);
declare #t005_pci_data table(FVBatch int
,pHValue decimal(10,2)
,Alcohol decimal(10,2)
,OG decimal(10,2)
,PG decimal(10,2)
,EBCHaze decimal(10,2)
,[DateTime] datetime
,Stage nvarchar(20)
,TankName nvarchar(20)
);
select b.FVBatch
,b.TankName
,b.BeerBrand
,case when((d.Stage in('CAN','BOTTLE','BBT')
and avg(cast(d.EBCHaze as dec(10,5))) > 5
)
or (avg(cast(d.Alcohol as dec(10,5))) not between max(s.ABV_lower) and max(s.ABV_upper)
or avg(cast(d.OG as dec(10,5))) not between max(s.OG_lower) and max(s.OG_upper)
or avg(cast(d.PG as dec(10,5))) not between max(s.PG_lower) and max(s.PG_upper)
or avg(cast(d.pHValue as dec(10,5))) not between max(s.pH_lower) and max(s.pH_upper)
)
)
then 'Red'
else 'Black'
end as Spec
from #t001_fvbatch b -- Always start at the table with the most central piece of data. In this case, the specifications and measurements all relate to a single batch.
left join #t024_specifications s
on(b.BeerBrand = s.BeerBrand
and s.[Type] = 'Finished Product'
)
inner join (select d2.FVBatch -- This sub select returns the most recent DateTime value per each FVBatch and TankName combination.
,d2.TankName
,cast(max(d2.[DateTime]) as date) as MostRecentMeasurement -- Cast/convert to DATE type to remove the TIME element. This means 2016-12-22 12:00:00 and 2016-12-22 13:59:43 both become 2016-12-22.
from #t005_pci_data d2
where d2.[DateTime] >= cast(dateadd(d -- This case statement filters the DateTime values by a number of days based on the value in the Stage column.
,case when d2.Stage in('can','bottle')
then -5
else -2
end
,getdate()
)
as date)
group by d2.FVBatch
,d2.TankName
) dm
on(b.FVBatch = dm.FVBatch
and b.TankName = dm.TankName
)
inner join #t005_pci_data d -- We then join into the data table again to get all the measurements taken on the same day as the most recent.
on(b.FVBatch = d.FVBatch
and b.TankName = d.TankName
and d.[DateTime] >= dm.MostRecentMeasurement -- Filtering like this allows any indexes on your DateTime column to be used to speed execution time. (This is called sargability).
and d.[DateTime] < dateadd(d,1,dm.MostRecentMeasurement) -- We could use functions to convert the DateTime to a DATE data type to match the MostRecentMeasurement value, but this would then need to be calculated for every single measurement in the table, which is wasteful.
)
-- Using INNER JOIN for the measurements means we are only return batches that have measurements that meet our filtering criteria.
-- If we wanted to return a batch even if there were no measurements matching, we would use LEFT JOIN instead.
group by b.FVBatch
,b.TankName
,b.BeerBrand
,d.Stage

Autogenerate numbers based on "Group" in GroupByExpression RadGrid and display it in RadGrid

I am having a trouble in implementing below requirement.
Current RadGrid: Below is the RadGrid in which I am using GroupByExpressions
to display/show data grouped with "Business Unit" column.
In RadGrid column 2nd(InvoiceLineNo) and 3rd(InvoiceNo), I am auto generating the numbers using Stored Procedure.
i.e., for "InvoiceLineNo" column, Autogenerated No's are: 01,02,03,04,05,06,07,08.......n
for "InvoiceNo" column, Autogenerated No's are: 15100001, 15100002, 15100003........n
where, 15 is a "year" and 100001 are "running numbers"
Requirement is: I want to show the "InvoiceLineNo" column data as Group wise.
Example:
for 1st "Business Unit" group (i.e., SUNWAY LEISURE SDN BHD (CARNIVAL)),
InvoiceLineNo shall be: 01,02,03,04,05,06,07,08
for 2nd "Business Unit" group (i.e., SUNWAY MALL PARKING SDN BHD),
InvoiceLineNo shall be: 01,02,03,04,05,06,07,08
Similarly, I want to show the "InvoiceNo" column data as Group wise.
Example:
for 1st "Business Unit" group (i.e., SUNWAY LEISURE SDN BHD (CARNIVAL)),
InvoiceNo shall be: 15100001,15100001,15100001,15100001,15100001,15100001,15100001,15100001
for 2nd "Business Unit" group (i.e., SUNWAY MALL PARKING SDN BHD),
InvoiceNo shall be: 15100002,15100002,15100002,15100002,15100002,15100002,15100002,15100002
"InvoiceNo" column data will always be unique for different "Business Unit".
I want output to be like below snapshot:
I can autogenerate the numbers serial wise but I am not getting how to autogenerate the 2 column values based on Group and show them like
that.
Please help me to achieve it. Please do reply.
Thanks in advance.
Edit:
Below is the Stored Procedure I am using to generate autogenerated numbers in RadGrid's 2 column's:
ALTER PROCEDURE [dbo].[SDM_Assign_RunningNo]
-- Add the parameters for the stored procedure here
#TableName as nvarchar(50),
#NewID as nvarchar(50) OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #rn_year as nvarchar(50)
--Get Year From table
SELECT #rn_year =RNYear FROM dbo.SDM_Tran_RunningNo
WHERE RNYear= YEAR(GetDate())
--get last 2 digits of year
Declare #2digit_rn_year as nvarchar(50)
SELECT #2digit_rn_year = RNYear % 100 FROM dbo.SDM_Tran_RunningNo
WHERE RNYear= YEAR(GetDate())
IF #TableName='SDM_Tran_GenerateInvoice_No'
BEGIN
SELECT #NewID=Next_InvoiceNo FROM dbo.SDM_Tran_RunningNo
WHERE RNYear=#rn_year
UPDATE dbo.SDM_Tran_RunningNo
SET Next_InvoiceNo=Next_InvoiceNo+1
WHERE RNYear=#rn_year
SET #NewID = #2digit_rn_year +'1'+RIGHT('000000' + CAST(#NewID as varchar(10)), 5)
END
ELSE IF #TableName='SDM_Tran_GenerateInvoice_LineNo'
BEGIN
SELECT #NewID=Next_InvoiceLineNo FROM dbo.SDM_Tran_RunningNo
WHERE RNYear=#rn_year
UPDATE dbo.SDM_Tran_RunningNo
SET Next_InvoiceLineNo=Next_InvoiceLineNo+1
WHERE RNYear=#rn_year
SET #NewID = RIGHT('000000' + CAST(#NewID as varchar(10)), 2)
END
END
And then inserting the 2 column values into Table as below (using Stored Procedure),
to display it in RadGrid:
DECLARE #InvoiceNo as nvarchar(50)
--SP to generate new Invoice No
EXEC dbo.SDM_Assign_RunningNo
#TableName='SDM_Tran_GenerateInvoice_No',
#NewID = #InvoiceNo OUTPUT
DECLARE #InvoiceLineNo as nvarchar(50)
--SP to generate new Invoice Line No
EXEC dbo.SDM_Assign_RunningNo
#TableName='SDM_Tran_GenerateInvoice_LineNo',
#NewID = #InvoiceLineNo OUTPUT
INSERT INTO SDM_Tran_GenerateInvoice
VALUES (#InvoiceID,
#SPfoID,
#InvoiceLineNo, #InvoiceNo, #InvoiceType,
#BillingIDfoID, #BusinessUnit, #DirectCost,
#Status, GETDATE(), #AccountCode)
This is a concept... you might need to modify it to suit your requirement.
DECLARE #Temp TABLE (
InvoiceID nvarchar(50),
SPfoID nvarchar(50),
InvoiceLineNo nvarchar(50),
InvoiceNo nvarchar(50),
InvoiceType nvarchar(50),
BillingIDfoID nvarchar(50),
BusinessUnit nvarchar(2000),
DirectCost nvarchar(2000),
Status nvarchar(10),
Date datetime,
AccountCode nvarchar(1000)
)
DECLARE #Temp1 TABLE (
OrderID INT IDENTITY, -- Added This so It Will follow this new Identity Row
InvoiceID nvarchar(50),
SPfoID nvarchar(50),
InvoiceLineNo nvarchar(50),
InvoiceNo nvarchar(50),
InvoiceType nvarchar(50),
BillingIDfoID nvarchar(50),
BusinessUnit nvarchar(2000),
DirectCost nvarchar(2000),
Status nvarchar(10),
Date datetime,
AccountCode nvarchar(1000)
)
DECLARE #CompanyValue nvarchar(2000) = '' --BusinessUnit datatype
DECLARE #Counter nvarchar(50) = '0' --InvoiceNo datatype
DECLARE #InvoiceLine INT = 1
DECLARE #Year INT = YEAR(GETDATE())
DECLARE #ShortYear VARCHAR(2) = SUBSTRING(CONVERT(VARCHAR(4), #Year), 3, 2)
EXEC dbo._RunningNo
#TableName='Invoice',
#NewID = InvoiceID --OUTPUT
INSERT INTO #Temp (InvoiceID, SPfoID, InvoiceType, BillingIDfoID, BusinessUnit, DirectCost, Status, Date, AccountCode)
SELECT InvoiceID, SPfoID, InvoiceType, BillingIDfoID, BusinessUnit, DirectCost, Status, Date, AccountCode FROM [MainTable] ORDER BY BusinessUnit
INSERT INTO #Temp1
SELECT * FROM #Temp ORDER BY BusinessUnit
SELECT * FROM #Temp
SELECT * FROM #Temp1 -- before update
--Update #Temp1 table
UPDATE #Temp1
SET
#Counter = InvoiceNo = CASE WHEN #CompanyValue = '' OR #CompanyValue = BusinessUnit THEN (CONVERT(VARCHAR(100), CONVERT(INT,#Counter) + 1)) ELSE '1' END,
#InvoiceLine = CASE WHEN #CompanyValue = '' OR #CompanyValue = BusinessUnit THEN #InvoiceLine ELSE #InvoiceLine + 1 END,
#CompanyValue = BusinessUnit,
InvoiceLineNo = #ShortYear + '10000' + CONVERT(VARCHAR(3), #InvoiceLine)
SELECT * FROM #Temp1 --after update
--Update main table
UPDATE g
SET g.InvoiceLineNo = t.InvoiceLineNo,
g.InvoiceNo = t.InvoiceNo
FROM SDM_Tran_GenerateInvoice g
INNER JOIN #Temp1 t
ON g.InvoiceID = t.InvoiceID
Select * from [MainTable]
ORDER BY BusinessUnit;

How to properly JOIN three different queries

I am using SQL Server 2008. I have three different queries that I would like to union together, but am unsure of how to properly go about it, as the structure of the queries are different.
My first query, creates two tables to insert records into for a comparison, where the MAX of a column for a visit is returned. Ex:
Query:
SET ANSI_NULLS OFF
GO
-- VARIABLE DECLARATION
DECLARE #STARTDATE DATETIME
DECLARE #ENDDATE DATETIME
-- VARIABLE INITIALIZATION
SET #STARTDATE = '6/1/12';
SET #ENDDATE = '1/1/13';
--#############################################################################################
-- TABLE DECLARATION WHICH WILL BE USED TO GET THE MAX ORDERED DATE #
-- #
DECLARE #T1 TABLE (ENCOUNTER VARCHAR(200), PT_NAME VARCHAR(500), MRN VARCHAR(200), --#
LOS VARCHAR(200), PT_LOC VARCHAR(500), PT_DISPO VARCHAR(500), --#
LAB_NAME VARCHAR(500), LAB_VALUE VARCHAR(40),LOWER_LIMIT VARCHAR(30), --#
UPPER_LIMIT VARCHAR(30), HISTORY VARCHAR(10), HAS_HISTORY VARCHAR(10), --#
AB_CODE VARCHAR(30), ORDER_ENTERED VARCHAR(500)) --#
DECLARE #T2 TABLE (ENCOUNTER2 VARCHAR(200), PT_NAME2 VARCHAR(500), MRN2 VARCHAR(200), --#
LOS2 VARCHAR(200), PT_LOC2 VARCHAR(500), PT_DISPO2 VARCHAR(500), --#
LAB_NAME2 VARCHAR(500), LAB_VALUE2 VARCHAR(40),LOWER_LIMIT2 VARCHAR(30), --#
UPPER_LIMIT2 VARCHAR(30), HISTORY2 VARCHAR(10), HAS_HISTORY2 VARCHAR(10),--#
AB_CODE2 VARCHAR(30), ORDER_ENTERED2 VARCHAR(500)) --#
-- #
--#############################################################################################
--## TABLE INSERTIONS ##
--###########################################################################################
--## WHAT GETS PUT INTO TABLE 1 ##
INSERT INTO #T1
SELECT
A.VisitIDCode,
A.ClientDisplayName,
A.IDCode,
A.LOS,
A.CurrentLocation,
A.DischargeDisposition,
A.ItemName,
A.Value,
A.ReferenceLowerLimit,
A.ReferenceUpperLimit,
A.IsHistory,
A.HasHistory,
A.AbnormalityCode,
A.Entered
FROM
(
-- COLUMN SELECTION
SELECT CV.VisitIDCode, CV.ClientDisplayName, CV.IDCode,DATEDIFF(DD,CV.ADMITDTM,CV.DISCHARGEDTM)AS 'LOS',
CV.CurrentLocation, CV.DischargeDisposition, BO.ItemName, BO.Value,
BO.ReferenceLowerLimit, BO.ReferenceUpperLimit, BO.IsHistory, BO.HasHistory, BO.AbnormalityCode,
BO.Entered
-- DB USED: SCM
FROM CV3ClientVisit CV
JOIN CV3BasicObservation BO
ON CV.GUID = BO.ClientVisitGUID
WHERE CV.AdmitDtm BETWEEN #STARTDATE AND #ENDDATE
AND CV.TypeCode = 'INPATIENT'
AND BO.Value IS NOT NULL
AND (BO.ItemName LIKE '%SODIUM LEVEL%'
OR BO.ITEMNAME LIKE '%HEMOG%')
)A
--## TABLE INSERTIONS ##
--###########################################################################################
--## WHAT GETS PUT INTO TABLE 2 ##
INSERT INTO #T2
SELECT
B.VisitIDCode,
B.ClientDisplayName,
B.IDCode,
B.LOS,
B.CurrentLocation,
B.DischargeDisposition,
B.ItemName,
B.Value,
B.ReferenceLowerLimit,
B.ReferenceUpperLimit,
B.IsHistory,
B.HasHistory,
B.AbnormalityCode,
B.Entered
FROM
(
-- COLUMN SELECTION
SELECT CV.VisitIDCode, CV.ClientDisplayName, CV.IDCode,DATEDIFF(DD,CV.ADMITDTM,CV.DISCHARGEDTM) AS 'LOS',
CV.CurrentLocation,CV.DischargeDisposition, BO.ItemName, BO.Value,BO.ReferenceLowerLimit, BO.ReferenceUpperLimit,
BO.IsHistory, BO.HasHistory, BO.AbnormalityCode,BO.Entered
-- DB USED: SCM
FROM CV3ClientVisit CV
JOIN CV3BasicObservation BO
ON CV.GUID = BO.ClientVisitGUID
WHERE CV.AdmitDtm BETWEEN #STARTDATE AND #ENDDATE
AND CV.TypeCode = 'INPATIENT'
AND BO.Value IS NOT NULL
AND (BO.ItemName LIKE '%SODIUM LEVEL%'
OR BO.ITEMNAME LIKE '%HEMOG%')
)B
--###########################################################################################
--## HERE IS WHERE WE DO TABLE COMPARISONS ##
SELECT
DISTINCT T1.ENCOUNTER,
T1.PT_NAME AS 'PT NAME', T1.MRN AS 'MRN', T1.LOS AS 'LOS', T1.PT_LOC AS 'PT LOC',
T1.PT_DISPO AS 'PT DISPO', T2.LAB_NAME2 AS 'LAB NAME', T2.LAB_VALUE2, T2.LOWER_LIMIT2 AS 'LOWER LIMIT',
T2.UPPER_LIMIT2 AS 'UPPER LIMIT', T2.AB_CODE2 AS 'AB CODE', T2.ORDER_ENTERED2
FROM #T1 T1
JOIN #T2 T2
ON T1.MRN = T2.MRN2
WHERE
T1.ENCOUNTER = T2.ENCOUNTER2
AND T1.ORDER_ENTERED < T2.ORDER_ENTERED2
AND T2.ORDER_ENTERED2 = (
SELECT MAX(TEMP.ORDER_ENTERED2)
FROM #T2 TEMP
WHERE T1.MRN = TEMP.MRN2
)
Results
CLIENT ID VISIT ID ARRIVE DATE VALUE DATE VALUE ORDERED
.......................................................................
1 | 1 | 1/1/13 | 5 | 1/1/13
1 | 1 | 1/1/13 | 6 | 1/2/13 <- returned row
Where this query will return the row with the date value ordered of 1/2/13.
The second query counts for me how many times the Client in the Client ID column came inside of a 12 month time frame. So for the above it would return something like
Query 2:
-- VARIABLE DECLARATION
DECLARE #STARTDATE DATETIME
DECLARE #ENDDATE DATETIME
-- INITIALIZE VARIABLES
SET #STARTDATE = '6/1/12';
SET #ENDDATE = '1/1/13';
-- COLUMN SELECTION
SELECT DISTINCT CV.IDCode AS 'MRN', COUNT(CV.IDCODE) AS 'COUNT OF IP VISITS'
FROM CV3ClientVisit CV
WHERE CV.AdmitDtm BETWEEN #STARTDATE AND #ENDDATE
AND CV.TypeCode LIKE '%INPATIENT'
AND CV.VisitStatus IN(
'ADM',
'DSC'
)
GROUP BY CV.IDCode
ORDER BY COUNT(CV.IDCode) DESC
Results:
Client ID Count of Visits
...............................
1 | 2
The third and final query tells me how many times they did something, for example
Query 3:
Declare #procedures Table (MRN varchar(20), Patient varchar(80), VisitID varchar(20), Admit datetime, Disch datetime, SurgProc varchar(200), ProcDesc varchar(200))
insert into #procedures
select cv.IDCode,cv.ClientDisplayName,cv.VisitIDCode,AdmitDtm,cv.DischargeDtm,ed.Description,ed.text from CV3ClientVisit cv
left join cV3ClientEventDeclaration ed
on cv.GUID=ed.ClientVisitGUID
where ed.typecode = 'Surgery'
and cv.AdmitDtm > '6/30/12' and cv.AdmitDtm <='1/1/13'
and Status = 'Active'
select visitid, COUNT(visitid)as '#Surg Procs' from #procedures
group by visitid
Results:
CLIENT ID VISIT ID ARRIVE DATE DEPART DATE COUNT OF PR VISITS
...............................................................................
1 | 1 | 1/1/13 | 1/3/13 | 3
So my question is, how do I properly JOIN all of these queries together in order to get just one result? There will be times where a client may not have a result for one of the queries.
I would like to final header to look something like this:
CLIENT ID | CLIENT VISIT ID | CLIENT NAME | LOS | PT LOC | PT DISPO | LAB NAME | LAB VALUE | LOWER LIMIT | UPPER LIMIT | AB CODE | COUNT OF IP VISITS | COUNT OF PROCEDURES
Thank You
OK. I'll give you a hint.
Let say you have two SELECT-type queries.
First returns: Last Name, First Name, Date of Birth.
Second returns: Last Name, First Name, Address, Occupation
You want the result as: Last Name, First Name, Occupation, Date of Birth, Address
You will do something like this:
SELECT LastName, FirstName, NULL, DOB, NULL FROM ...
UNION
SELECT LastName, FirstName, Occupation, NULL, Address FROM ...

Inproving speed of T-SQL script

I need to improve the speed dramatically for the following script. I am thinking about removing the table valued function and placing everything in the stored procedure. But before I do it I wanted to get the experts to take a look and provide me with a solution or a few pointers. The scripting has paging functionality which needs to remain in place somehow.
Here firstly is the Store procedure:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROC [sbuser].[sp_MemberSearch]
#UserName varchar(200) = null,
#MemberID bigint = null,
#PG int = 1,
#ROWCT numeric(18,2) = 1,
#COLCT numeric(18,2) = 1,
#MODE varchar(50)
AS
IF #MODE = 'MEMBERSEARCH'
BEGIN
SELECT
MemberID, -- 0
UserName, -- 1
LastLogin, -- 2
PrCity, -- 3
Abbr, -- 4
Country, -- 5
AvatarMed, -- 6
Gender, -- 7
HasImages, -- 8
HasVideo, -- 9
HasAudio, -- 10
Domain, -- 11
DisplayName, -- 12
CreateDate, -- 13
Claimed, -- 14
PG, -- 15
MAXPG, -- 16
TOTALRECS, -- 17
ProfileTypeID, -- 18
Zip, -- 19
PhoneNbr, -- 20
PrPhone -- 21
FROM sbuser.tf_FindMember(#UserName,#MemberID,#PG,#ROWCT,#COLCT)
END
and here is the table valued function as named above:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [sbuser].[tf_FindMember] (
#UserName varchar(200) = null,
#MemberID bigint = null,
#PG int = 1,
#ROWCT numeric(18,2) = 1,
#COLCT numeric(18,2) = 1 )
RETURNS #OUT TABLE (
MemberID bigint, -- 0
UserName varchar(200), -- 1
LastLogin datetime, -- 2
PrCity varchar(50), -- 3
Abbr varchar(5), -- 4
Country varchar(50), -- 5
AvatarMed varchar(50), -- 6
Gender varchar(50), -- 7
HasImages bit, -- 8
HasVideo bit, -- 9
HasAudio bit, -- 10
Domain varchar(100), -- 11
DisplayName varchar(255), -- 12
CreateDate datetime, -- 13
Claimed varchar(1), -- 14
PG int, -- 15
MAXPG int, -- 16
TOTALRECS int, -- 17
ProfileTypeID bigint, -- 18
Zip varchar(50), -- 19
PhoneNbr varchar(50), -- 20
PrPhone varchar(25)) -- 21
AS
BEGIN
DECLARE #START numeric(18,2)
DECLARE #END numeric(18,2)
DECLARE #SIZE numeric(18,2)
DECLARE #MAXPG numeric(18,2)
DECLARE #TOTALRECS numeric(18,2)
DECLARE #TOTALRECS_INT int
DECLARE #MAXPG_INT int
DECLARE #TOTALRECS_REMAINDER numeric(18,2)
SET #SIZE = #ROWCT * #COLCT
SET #Start = (((#PG - 1) * #Size) + 1)
SET #END = (#START + #SIZE - 1)
DECLARE #TMP1 TABLE (
TMPID bigint primary key identity(1,1),
MemberID bigint,
UserName varchar(200),
LastLogin datetime,
PrCity varchar(50),
Abbr varchar(5),
Country varchar(50),
AvatarMed varchar(50),
Gender varchar(50),
HasImages bit,
HasVideo bit,
HasAudio bit,
Domain varchar(100),
DisplayName varchar(255),
CreateDate datetime,
Claimed varchar(1),
ProfileTypeID bigint,
Zip varchar(50),
PhoneNbr varchar(50),
PrPhone varchar(25))
BEGIN
INSERT INTO #TMP1
SELECT
a.MemberID,
a.UserName,
a.LastLogin,
a.PrCity,
b.Abbr,
c.Country,
a.AvatarMed,
a.Gender,
sbuser.sf_MemberHasImages(a.MemberID),
sbuser.sf_MemberHasVideo(a.MemberID),
sbuser.sf_MemberHasAudio(a.MemberID),
d.Domain,
sbuser.sf_DisplayName(a.MemberID),
a.CreateDate,
a.Claimed,
a.ProfileTypeID,
a.Zip,
a.PhoneNbr,
a.PrPhone
FROM Member a
LEFT JOIN State b ON b.StateID = a.StateID
INNER JOIN Country c ON c.countryID = a.CountryID
INNER JOIN Region d ON d.RegionID = a.MemberRegionID
WHERE (sbuser.sf_DisplayName(a.MemberID) LIKE #UserName + '%')
AND a.MemberID <> #MemberID
ORDER BY a.Claimed DESC, sbuser.sf_MemberHasAvatar(a.MemberID) DESC, sbuser.sf_MemberHasMedia(a.MemberID) DESC
END
SELECT #TOTALRECS = MAX(TMPID) FROM #TMP1
SELECT #MAXPG = #TOTALRECS / #SIZE
SET #TOTALRECS_REMAINDER = #TOTALRECS % #SIZE
SET #MAXPG_INT = CAST(#MAXPG AS INT)
SET #TOTALRECS_INT = CAST(#TOTALRECS AS INT)
IF #TOTALRECS_REMAINDER > 0
BEGIN
SET #MAXPG_INT = #MAXPG_INT + 1
END
INSERT INTO #OUT
SELECT
MemberID,
UserName,
LastLogin,
PrCity,
Abbr,
Country,
AvatarMed,
Gender,
HasImages,
HasVideo,
HasAudio,
Domain,
DisplayName,
CreateDate,
Claimed,
#PG,
#MAXPG_INT,
#TOTALRECS_INT,
ProfileTypeID,
Zip,
PhoneNbr,
PrPhone
FROM #TMP1
WHERE (TmpID >= #Start) AND (TmpID <= #END)
RETURN
END
I believe this script was written by software, by my predecessor. I don't have much experience with T-SQL. I would really appreciate any help you can give to improve the execution speed as now our system has over 40,000 members it has gotten extremely slow.
Many thanks for taking a look. I really appreciate it!
Best Regards,
Paul Jacobs
To further assist here are the missing sf scripts:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [sbuser].[sf_MemberHasImages](#MemberID bigint)
RETURNS BIT
AS
BEGIN
DECLARE #OUT BIT
SET #OUT = (SELECT CAST(COUNT(a.MemberImgID) AS BIT) From MemberImg a INNER JOIN MemberImgGallery b ON b.MemberImgGalleryID=a.MemberImgGalleryID
WHERE b.MemberID = #MemberID)
RETURN #out
END
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [sbuser].[sf_MemberHasAudio](#MemberID bigint)
RETURNS BIT
AS
BEGIN
DECLARE #OUT BIT
SET #OUT = (SELECT CAST(COUNT(MemberAudioID) AS BIT) FROM MemberAudio WHERE MemberID = #MemberID)
RETURN #OUT
END
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [sbuser].[sf_MemberHasVideo](#MemberID bigint)
RETURNS BIT
AS
BEGIN
DECLARE #OUT BIT
SET #OUT = (SELECT CAST(COUNT(MemberVideoID) AS BIT) FROM MemberVideo WHERE MemberID = #MemberID)
RETURN #OUT
END
Looking at the code you've posted, the flow basically is like this:
a stored proc calls a UDF.
---- not perf related, but why is this string being sent to a stored proc named the same? IF #MODE = 'MEMBERSEARCH' in a proc called [sp_MemberSearch]. Seems superfluous from this once-over review of the code.
this should NOT call a UDF. Suggest refactoring the code to have all the searching in the stored proc. Likely today it's being used from many stored procs, so it's easily re-used in the current setup. Not horrible, but you can do it another way, especially if you're using SQL Server 2008. Try re-architecting it as its own stored proc.
The UDF basically performs a select with 3 important pieces/considerations:
(sbuser.sf_DisplayName(a.MemberID) LIKE #UserName + '%'). To me, this is implying that EACH member ID is being passed into the function, and evaluated against the LIKE condition.
ORDER BY 2 different results of UDFs - MemberHasAvatar and MemberHasMedia -- obviously wanting those to be ordered at the top.
The 4 tables: Member, State, Country, Region -- are they indexed properly on the JOINed columns? How well does this SELECT perform when you run this statement without any/some/all of that WHERE clause and ORDER BY clause?
the paging aspects could be improved to use newer TSQL language features, but it could be more than you wanted to take on. ROW_NUMBER() being part of that improvement.
it's not clear what the real-world meaning of this clause is: WHERE (sbuser.sf_DisplayName(a.MemberID) LIKE #UserName + '%')
AND a.MemberID <> #MemberID
Does it mean that we don't want to include the #MemberID in the search results because they're the member performing the search? Probably a better variable name is suitable like #SearchPerformedByMemberID?
The math part, as you probably already know, won't have any measurable performance impact on this function/proc.
Some suggestions for improvement, YMMV!
Suggest storing the DisplayName on the Member table to avoid having to call sbuser.sf_DisplayName.