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

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;

Related

Replace Cursor Next number assignment Operation with Set based equivalent

Good day all,
I have the following cursor query and would like to replace it with a set based query to address performance issues.
DECLARE #EmpIDM CHAR(21);
DECLARE #EmpName CHAR(21);
DECLARE #EMPCatID INT;
DECLARE Assign_Emp SCROLL CURSOR
FOR
SELECT DISTINCT EMP
, EMPNAME
FROM HR_EMPLOYEES
SET NOCOUNT ON
OPEN Assign_Emp;
FETCH NEXT
FROM Assign_Emp
INTO #EmpIDM
, #EmpName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #EMPCatID = (
SELECT TOP 1 CategoryID
FROM Categories
)
UPDATE Categories
SET CategoryID = (CategoryID + 1) /*Increment Category ID for next Insert*/
INSERT INTO Table1 (
EmpNumber
, EmployeeName
, EmployeeCategoryID
)
VALUES (
#EmpIDM
, #EmpName
, #EMPCatID
)
FETCH NEXT
FROM Assign_Emp
INTO #EmpIDM
, #EmpName
END
CLOSE Assign_Emp;
CLOSE Assign_Emp;
SET NOCOUNT OFF
My challenge is adapting the following code segment into a set based operation
SET #EMPCatID = (
SELECT TOP 1 CategoryID
FROM Categories
)
UPDATE Categories
SET CategoryID = (CategoryID + 1) /*Increment Category ID for next Insert*/
I humbly appreciate any insight on how I can achieve this.
Many Thanks,
Re-write using temp. table with identity column:
declare #offset int
select #offset = isnull(max(CategoryID),0) from Categories
create table #data (
EmpNumber CHAR(21),
EmployeeName CHAR(21),
EmployeeCategoryID int identity
)
INSERT INTO #data (
EmpNumber
, EmployeeName)
SELECT DISTINCT EmpIDM
, EmpName
FROM HR_EMPLOYEES
insert into Table1 (
EmpNumber
, EmployeeName
, EmployeeCategoryID
) select
EmpNumber
, EmployeeName
, EmployeeCategoryID + #offset
from #data
update Categories
set CategoryID = (select max(EmployeeCategoryID) from #data) + #offset

SQL TRANSACTION Begin End mismatch?

Although I am able to create stored procedure successfully I am getting "TRANSACTION BEGIN END MISMATCH" error upon using it. The stored Procedure works fine when I remove transaction.
ALTER PROCEDURE Proc_LoanRepayment #LASAcctno [VARCHAR] (15),
#EntryDate [VARCHAR] (8),
#ValueDate [VARCHAR] (8),
#ModeofPayment VARCHAR(20),
#ChqNo VARCHAR(20),
#ChqDate VARCHAR(8),
#ChqAmt MONEY,
#CstBnkNo VARCHAR(20),
#Cstbnkid VARCHAR(20),
#CmpBnkNo VARCHAR(20),
#Cmpbnkid VARCHAR(20),
#Narration1 [VARCHAR] (100),
#Narration2 [VARCHAR] (100),
#EntryType VARCHAR(30),
#PostingString [VARCHAR] (max)
AS
BEGIN TRAN
DECLARE #string AS VARCHAR(max)
DECLARE Cur_A CURSOR FOR
SELECT *
FROM dbo.split(#PostingString, ',')
OPEN Cur_a
FETCH NEXT FROM cur_a INTO #string
WHILE ##FETCH_STATUS = 0
BEGIN
IF ( object_id('TempDB..#Temp') ) IS NOT NULL
BEGIN
DROP TABLE #Temp
END
-- declare #temp table (srno int identity,items varchar(max))
SELECT *
INTO #temp
FROM dbo.Split(#string, '|')
DECLARE #LoanNo AS VARCHAR(20),
#BankAcct AS VARCHAR(20),
#TDS AS MONEY,
#LASPAC AS MONEY,
#INTRND AS MONEY,
#INTRAC AS MONEY,
#STAXPLRVL AS MONEY,
#PNLINT AS MONEY,
#OVRDUEINT AS MONEY,
#STMPDTYRVL AS MONEY,
#PROFESRVL AS MONEY,
#DOCCHGRVL AS MONEY,
#CHQBNCRVL AS MONEY
ALTER TABLE #temp
ADD srno INT IDENTITY
SELECT #LoanNo = items
FROM #temp
WHERE srno = 1
SELECT #bankAcct = items
FROM #temp
WHERE srno = 2
SELECT #TDS = items
FROM #temp
WHERE srno = 3
SELECT #LASPAC = items
FROM #temp
WHERE srno = 4
SELECT #INTRND = items
FROM #temp
WHERE srno = 5
SELECT #INTRAC = items
FROM #temp
WHERE srno = 6
SELECT #STAXPLRVL = items
FROM #temp
WHERE srno = 7
SELECT #PNLINT = items
FROM #temp
WHERE srno = 8
SELECT #OVRDUEINT = items
FROM #temp
WHERE srno = 9
SELECT #STMPDTYRVL = items
FROM #temp
WHERE srno = 10
SELECT #PROFESRVL = items
FROM #temp
WHERE srno = 11
SELECT #DOCCHGRVL = items
FROM #temp
WHERE srno = 12
SELECT #CHQBNCRVL = items
FROM #temp
WHERE srno = 13
INSERT INTO Tbl_BankEntry
(LASAcctno,
EntryDate,
ValueDate,
ModeofPayment,
ChqNo,
ChqDate,
ChqAmt,
CstBnkNo,
Cstbnkid,
CmpBnkNo,
Cmpbnkid,
Narration1,
Narration2,
LoanNo,
BankAcct,
TDS,
LASPAC,
INTRND,
INTRAC,
STAXPLRVL,
PNLINT,
OVRDUEINT,
STMPDTYRVL,
PROFESRVL,
DOCCHGRVL,
CHQBNCRVL,
status,
mkrdt,
mkrid,
EntryType)
VALUES ( #LASAcctno,
#EntryDate,
#ValueDate,
#ModeofPayment,
#ChqNo,
#ChqDate,
#ChqAmt,
#CstBnkNo,
#Cstbnkid,
#CmpBnkNo,
#Cmpbnkid,
#Narration1,
#Narration2,
#LoanNo,
#BankAcct,
#TDS,
#LASPAC,
#INTRND,
#INTRAC,
#STAXPLRVL,
#PNLINT,
#OVRDUEINT,
#STMPDTYRVL,
#PROFESRVL,
#DOCCHGRVL,
#CHQBNCRVL,
'P',
GETDATE(),
'c97176',
#EntryType )
FETCH NEXT FROM Cur_a INTO #string
END
CLOSE cur_a
DEALLOCATE cur_a
RETURN
COMMIT TRAN
Your RETURN statement is before your COMMIT statement.
Suggest you look into #Martin Smith's sugegstion of using table valued parameters rather than splitting strings (SQL Server 2008+), and # Damien_The_Unbeliever's suggestion of the expected ordering.
Also, try to rewrite procedure so that it doesn't require a cursor, and that you do the least amount possible of work inside the transaction.
Also, look at TRY/CATCH and checking whether there is an active transaction (##TRANCOUNT) before commiting.

Loop through a recordset and use the result to do another SQL select and return the results

I am completely new to stored procedure. This time, I need to create a stored procedure in MS SQL.
Let's say I have the following table.
Table name: ListOfProducts
--------------------------
SomeID, ProductID
34, 4
35, 8
35, 11
How do I pass in a SomeID. Use this SomeID to select a recordset from table, ListOfProducts. Then loop through this record set.
Let's say I pass in SomeID = 35.
So, the record set will return 2 records with SomeID 35. In the loop, I will get ProductID 8 and 11, which will be used to do another select from another table.
The stored procedure should return the results from the 2nd select.
How can I do this in MS SQL stored procedure?
Sorry, for this newbie question. Thanks for any help.
If you want looping through the records. You can do like:
--Container to Insert Id which are to be iterated
Declare #temp1 Table
(
tempId int
)
--Container to Insert records in the inner select for final output
Declare #FinalTable Table
(
Id int,
ProductId int
)
Insert into #temp1
Select Distinct SomeId From YourTable
-- Keep track of #temp1 record processing
Declare #Id int
While((Select Count(*) From #temp1)>0)
Begin
Set #Id=(Select Top 1 tempId From #temp1)
Insert Into #FinalTable
Select SomeId,ProductId From ListOfProducts Where Id=#Id
Delete #temp1 Where tempId=#Id
End
Select * From #FinalTable
There is probably no point in writing an explicit loop if you don't need to preform some action on the products that can't be done on the whole set. SQL Server can handle stuff like this much better on its own. I don't know what your tables look like, but you should try something that looks more like this.
CREATE PROC dbo.yourProcName
#SomeID int
AS
BEGIN
SELECT
P.ProductId,
P.ProductName
FROM
Product P
JOIN
ListOfProducts LOP
ON LOP.ProductId = P.ProductId
WHERE
LOP.SomeId = #SomeID
END
I had to do something similar in order to extract hours from a select resultset start/end times and then create a new table iterating each hour.
DECLARE #tCalendar TABLE
(
RequestedFor VARCHAR(50),
MeetingType VARCHAR(50),
RoomName VARCHAR(MAX),
StartTime DATETIME,
EndTime DATETIME
)
INSERT INTO #tCalendar(RequestedFor,MeetingType,RoomName,StartTime,EndTime)
SELECT req as requestedfor
,meet as meetingtype
,room as rooms
,start as starttime
,end as endtime
--,u.datetime2 as endtime
FROM mytable
DECLARE #tCalendarHours TABLE
(
RequestedFor VARCHAR(50),
MeetingType VARCHAR(50),
RoomName VARCHAR(50),
Hour INT
)
DECLARE #StartHour INT,#EndHour INT, #StartTime DATETIME, #EndTime DATETIME
WHILE ((SELECT COUNT(*) FROM #tCalendar) > 0)
BEGIN
SET #StartTime = (SELECT TOP 1 StartTime FROM #tCalendar)
SET #EndTime = (SELECT TOP 1 EndTime FROM #tCalendar)
SET #StartHour = (SELECT TOP 1 DATEPART(HOUR,DATEADD(HOUR,0,StartTime)) FROM #tCalendar)
SET #EndHour = (SELECT TOP 1 DATEPART(HOUR,DATEADD(HOUR,0,EndTime)) FROM #tCalendar)
WHILE #StartHour <= #EndHour
BEGIN
INSERT INTO #tCalendarHours
SELECT RequestedFor,MeetingType,RoomName,#StartHour FROM #tCalendar WHERE StartTime = #StartTime AND EndTime = #EndTime
SET #StartHour = #StartHour + 1
END
DELETE #tCalendar WHERE StartTime = #StartTime AND EndTime = #EndTime
END
Do something like this:
Declare #ID int
SET #ID = 35
SELECT
p.SomeID
,p.ProductID
FROM ListOfProducts p
WHERE p.SomeID = #ID
-----------------------
--Or if you have to join to get it
Declare #ID int
SET #ID = 35
SELECT
c.SomeID
,p.ProductID
,p.ProductName
FROM ListOfProducts p
INNER JOIN categories c on p.ProductID = c.SomeID
WHERE p.SomeID = #ID
You can use option with WHILE loop and BREAK/CONTINUE keywords
CREATE PROC dbo.yourProcName
#SomeID int
AS
BEGIN
IF OBJECT_ID('tempdb.dbo.#resultTable') IS NOT NULL DROP TABLE dbo.#resultTable
CREATE TABLE dbo.#resultTable
(Col1 int, Col2 int)
DECLARE #ProductID int = 0
WHILE(1=1)
BEGIN
SELECT #ProductID = MIN(ProductID)
FROM ListOfProducts
WHERE SomeID = #SomeID AND ProductID > #ProductID
IF #ProductID IS NULL
BREAK
ELSE
INSERT dbo.#resultTable
SELECT Col1, Col2
FROM dbo.yourSearchTable
WHERE ProductID = #ProductID
CONTINUE
END
SELECT *
FROM dbo.#resultTable
END
Demo on SQLFiddle

SQL: create new table with distinct value and max/min values for other columns w/in an existing table

Example:
Suppose the original table contains the following values
AcctNbr StatusDate
------------------
123 01/01/2012
123 01/01/2013
123 12/11/2011
987 01/01/2009
The SQL would create a new table containing
AcctNbr EarliestStatusDate LatestStatusDate
-------------------------------------------
123 12/11/2011 01/01/2013
987 01/01/2009 01/01/2009
I'm looking for an efficient way to do this. I have a method that works, but it takes an unacceptably long time. Does anyone have any optimization tips. Any help would be greatly appreciated.
SET NOCOUNT ON
DROP TABLE loopTemp
DROP TABLE reportTemp
CREATE TABLE loopTemp
( ID int IDENTITY(1, 1) NOT NULL,
AcctNbr varchar(50),
)
CREATE TABLE reportTemp
(
AcctNbr varchar(50),
EarliestStatus Date,
LatestStatus Date
)
INSERT INTO loopTemp
SELECT DISTINCT AcctNbr
FROM AutoStatusHistory
DECLARE #COUNTER AS INT
SET #COUNTER = 1
DECLARE #MAX AS INT
SET #MAX = (SELECT MAX(ID) FROM loopTemp)
WHILE #COUNTER < #MAX BEGIN
DECLARE #ACCOUNT_NUMBER AS varchar(50)
SET #ACCOUNT_NUMBER =
(SELECT AcctNbr FROM loopTemp WHERE ID = #COUNTER)
DECLARE #EARLIESTSTATUSDATE AS DATE
SET #EARLIESTSTATUSDATE = (SELECT MIN(NewStatusDate)
FROM AutoStatusHistory
WHERE AcctNbr = #ACCOUNT_NUMBER)
DECLARE #LATESTSTATUSDATE AS DATE
SET #LATESTSTATUSDATE = (SELECT MAX(NewStatusDate)
FROM AutoStatusHistory
WHERE AcctNbr = #ACCOUNT_NUMBER)
INSERT INTO reportTemp
VALUES (#ACCOUNT_NUMBER, #EARLIESTSTATUSDATE, #LATESTSTATUSDATE)
IF (#COUNTER % 1000) = 0 BEGIN
PRINT #COUNTER
END -- IF
SET #COUNTER = #COUNTER + 1
END -- WHILE
DROP TABLE loopTemp
Unless I'm missing something, this should be extremely simple:
SELECT AcctNbr, MIN(StatusDate) AS EarliestStatusDate,
MAX(StatusDate) AS LatestStatusDate
FROM myTable
GROUP BY AcctNbr
You appear to be using SQL Server. For this, you can do:
select AcctNbr, min(StatusDate) as EarliestStatusDate,
max(StatusDate) as LatestStatusDate
into ReportTemp
from AutoStatusHistory
group by AcctNbr
The into statement saves the results into a table. You might want to use an actual temporary table, with the syntax:
into #ReportTemp
You can use
SELECT *
INTO TableName
FROM (
SELECT AcctNbr, MIN([Status Date]) AS EarliestStatusDate,
MAX([Status Date]) AS LatestStatusDate
FROM myTable
GROUP BY AcctNbr
) RequiredData

SQL: Retrieving Unique ID with Multiple Attributes

Ok, I had trouble describing this. I have:
material table (materialID, material, etc...)
ThicknessRange table (ThicknessRangeID, ThicknessRange)
MaterialThicknessRange table (MaterialID, ThicknessRangeID)
I am trying to retrieve all MaterialID's from the MaterialThicknessRange table that fit all required ThicknessRangeID's.
For example, any MaterialID with ThicknessRangeID 1 AND ThicknessRangeID 2, etc with a variable number of ThicknessRangeID's (selected from checkboxes by the user).
Thanks in advance.
Are you guaranteed to have only one entry in the MaterialThicknessRange table for a given Material/ThicknessRange combination?
SELECT MaterialID, COUNT(MaterialID) As NumMaterialThicknesses
FROM MaterialThicknessRange
WHERE ThicknessRangeID IN (1, 2)
GROUP BY MaterialID
HAVING COUNT(MaterialID) > 1
I'm using something like this
select MaterialID from MaterialThicknessRange MTR inner join
dbo.TransformCSVToTable('1,2,15') IDs on MTR.ThiknessRangeID = IDs.ID
where dbo.TransformCSVToTable is a user defined function to transform a csv string to a one column table. Bellow is one sample of such function
ALTER FUNCTION [dbo].[fn_IntegerParameterListFromString]
(
#IntegerParameterList varchar(max)
)
RETURNS #result TABLE (IntegerID int)
AS
begin
declare #temp table (IntegerID int)
declare #s varchar(max), #s1 varchar(10)
declare #len int
set #len =len(#IntegerParameterList)
set #s = #IntegerParameterList
if (right(#s,1)<>',') set #s = #s +','
while #s<>''
begin
set #s1 = substring(#s,1,charindex(',',#s)-1)
if (isnumeric(#s1)= 1)
insert #result (IntegerID) Values ( Cast(#s1 as int))
if (CHARINDEX(',',#s)>0)
begin
set #s = substring (#s, charindex(',',#s)+1, #Len)
end
else
begin
if isnumeric(#s) = 1
insert #result (IntegerID) Values ( Cast(#s as int))
set #s = ''
end
end
return
end