CREATE PROCEDURE [dbo].[sp_GetPageWiseData]
(
#tableName sysname,
#orderColumn nvarchar(100),
#PageIndex INT = 1,
#PageSize INT = 10,
#RecordCount varchar(10) OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #query varchar(2000),
#minimumIndex varchar(5),
#maximumIndex varchar(5)
SET #minimumIndex=convert(varchar,(#PageIndex - 1) * #PageSize + 1)
SET #maximumIndex=convert(varchar,#PageIndex * #PageSize)
SET #query='SELECT ROW_NUMBER() OVER(ORDER BY ' + #orderColumn + ' ASC)AS RowNumber,* INTO #Results FROM ' + #tableName + ';
SELECT ' + #RecordCount + '=COUNT(*) FROM #Results;
SELECT * FROM #Results WHERE RowNumber BETWEEN ' + #minimumIndex + ' AND ' + #maximumIndex + ';
DROP TABLE #Results'
Exec (#query)
END
Here is the problem is when the procedure is executed, output parameter #RecordCount shows NULL value.
WHY?
Please explain.
Thanks
Your query must be like this:
SET #query='SELECT ROW_NUMBER() OVER(ORDER BY ' + #orderColumn + ' ASC)AS RowNumber,* INTO #Results FROM ' + #tableName + ';
SELECT #RecordCount =COUNT(*) FROM #Results;
SELECT * FROM #Results WHERE RowNumber BETWEEN ' + #minimumIndex + ' AND ' + #maximumIndex + ';
DROP TABLE #Results';
But here system will ask you to declare the variable, #RecordCount
so you can do it like this by returning 2 datasets from the query;
SET #query='DECLARE #RecordCount varchar(10); SELECT ROW_NUMBER() OVER(ORDER BY ' + #orderColumn + ' ASC)AS RowNumber,* INTO #Results FROM ' + #tableName + ';
SELECT #RecordCount =COUNT(*) FROM #Results;
SELECT * FROM #Results WHERE RowNumber BETWEEN ' + #minimumIndex + ' AND ' + #maximumIndex + ';
SELECT #RecordCount AS TOTALRECORDS;
DROP TABLE #Results';
I think you cant use it on this way. It's like concatanation not a value assign method. I think you should handle it in two steps, something like this:
SET #query='SELECT ROW_NUMBER() OVER(ORDER BY ' + #orderColumn + ' ASC)AS RowNumber,* INTO #Results FROM ' + #tableName + ';'
Exec (#query)
SELECT #RecordCount =COUNT(*) FROM #Results
SET #query='SELECT * FROM #Results WHERE RowNumber BETWEEN ' + #minimumIndex + ' AND ' + #maximumIndex + ';
DROP TABLE #Results'
Exec (#query)
Related
I have a View in AX with a computed column:
private static server str qty()
{
#define.THEN(" THEN ")
#define.SINGLE_QUOTE("'")
return 'CASE T2.ReturnStatus ' +
' WHEN ' + int2str(enum2int(ReturnStatusLine::None)) + #THEN + '-1 * T3.UnitValue' +
' WHEN ' + int2str(enum2int(ReturnStatusLine::Awaiting)) + #THEN + '-1 * T3.UnitValue' +
' WHEN ' + int2str(enum2int(ReturnStatusLine::Registered)) + #THEN + '-1 * T3.UnitValue' +
' ELSE ' + "(T3.UnitValue / T2.ExpectedRetQty * (SELECT TOP 1 SUM(cpst.Qty) as RcvQty from custPackingSlipTrans as cpst where cpst.InventTransId = T2.InventTransId and cpst.dataAreaId='" + curext() + "')) * -1" +
' END';
}
It works great, except the past week or so the column is returning NULL when it should not be. This is fixed simply by going into the AOT and syncing this view, after that the column has a valid value. But we're having to do this almost daily.
Any ideas?
I'm using tSqlt to unit test a stored procedure. This stored proc joins to a table-valued function, the function takes no parameters and the results are filtered via the join on clause.
I'm writing multiple tests for the stored proc. Is there a way to to fake the function in such a way that I could return different results based on the test that is being run.
The only solution I can think of is to create a fake per test, which is possible but a little more than clunky.
I imagine an ideal solution would be some sort of variable exposed in tsqlt that would allow me to determine which test I'm in and use some sort of case statement or something.
I use following procedure for that. It is not ideal, but working:
CREATE PROCEDURE [tSQLt].[FakeFunction2]
#FunctionName VARCHAR(200)
, #SchemaName VARCHAR(200) = 'dbo'
, #tmpTableName VARCHAR(200)
AS
BEGIN
DECLARE #Params VARCHAR(2000);
DECLARE #NewName VARCHAR(MAX) = #FunctionName + REPLACE(CAST(NEWID() AS VARCHAR(100)), '-', '');
DECLARE #FunctionNameWithSchema VARCHAR(MAX) = #SchemaName + '.' + #FunctionName;
DECLARE #RenameCmd VARCHAR(MAX) = 'EXEC sp_rename ''' + #FunctionNameWithSchema + ''', ''' + #NewName + ''';';
DECLARE #newTbleName VARCHAR(200) = #SchemaName + '.tmp' + REPLACE(CAST(NEWID() AS VARCHAR(100)), '-', '');
DECLARE #newTblStmt VARCHAR(2000) = 'SELECT * INTO ' + #newTbleName + ' FROM ' + #tmpTableName;
EXEC tSQLt.SuppressOutput #command = #newTblStmt;
SELECT #Params = p.params
FROM
( SELECT DISTINCT ( SELECT p1.name + ' ' + type1.name + b.brk + ',' AS [text()]
FROM sys.types type1
JOIN sys.parameters p1 ON p1.system_type_id = type1.system_type_id
CROSS APPLY
( SELECT CASE WHEN type1.name LIKE '%char' OR type1.name = 'varbinary' THEN
REPLACE(
'(' + CAST(p1.max_length AS VARCHAR(5)) + ')', '-1', 'MAX')
WHEN type1.name IN ('decimal', 'numeric') THEN
'(' + CAST(p1.precision AS VARCHAR(5)) + ', '
+ CAST(p1.scale AS VARCHAR(5)) + ')'
WHEN type1.name IN ('datetime2') THEN
'(' + CAST(p1.scale AS VARCHAR(5)) + ')'
ELSE ''
END AS brk) b
WHERE p1.object_id = p.object_id
ORDER BY p1.parameter_id
FOR XML PATH('')) [parameters]
FROM sys.objects AS o
LEFT JOIN sys.parameters AS p ON p.object_id = o.object_id
LEFT JOIN sys.types AS t ON t.system_type_id = p.system_type_id
WHERE o.name = #FunctionName AND o.schema_id = SCHEMA_ID(#SchemaName)) [Main]
CROSS APPLY
(SELECT LEFT(Main.[parameters], LEN(Main.[parameters]) - 1) params) AS p;
EXEC tSQLt.SuppressOutput #command = #RenameCmd;
DECLARE #newFunctionStmt VARCHAR(MAX) = '';
SET #newFunctionStmt = 'CREATE FUNCTION [' + #SchemaName + '].[' + #FunctionName + '](' + COALESCE(#Params,'') + ')';
SET #newFunctionStmt = #newFunctionStmt + ' RETURNS TABLE AS RETURN (SELECT * FROM ' + #newTbleName + ');';
EXEC tSQLt.SuppressOutput #command = #newFunctionStmt;
END;
and usage:
INSERT INTO #table
(col1
, col2
, col3)
VALUES
('a', 'b', 'c'),
('d', 'e', 'f');
EXEC tSQLt.FakeFunction2 #FunctionName = 'function_name'
, #SchemaName = 'dbo'
, #tmpTableName = '#table';
now with any passed parameter to that function it will always return the values from #table temp table
I thought of one potential solution.
I create a table within the test class schema and populate it with the results I wish to be returned per test.
CREATE TABLE testcalass.fakefunction_Results
(
ID INT,
Value NUMERIC(12, 5)
)
GO
CREATE FUNCTION testcalass.fakefunction()
RETURNS #results TABLE
(
ID INT,
Value NUMERIC(12, 5)
)
BEGIN
INSERT INTO #results
SELECT ID, Value FROM testcalass.fakefunction_Results
END
GO
So basically, I can populate is functions results at the top of my tests during the assemble section.
I need help on optimizing this query that retrieves a list of products from businesses. This query only brings set of data using specific parameters you see below. It takes about 6-9 seconds to run with about 40,000 products and only brings 10 products at a time, but I need to make it faster.
I execute this:
EXEC [GetProducts] #StartRowIndex=0, #MaximumRows=10,
#SortedBy='ProductName', #SortedIn='DESC', #CategoryID=0,
#CategoryIDPath=N'''1|%''', #SearchText='ALL', #SearchSQL=N'', #CreatedByUser=0
Here's the full query:
ALTER PROCEDURE [GetProducts] (
#StartRowIndex int,
#MaximumRows int,
#SortedBy nvarchar(20),
#SortedIn nvarchar(6),
#CategoryID int,
#CategoryIDPath nvarchar(500),
#SearchText nvarchar(255),
#SearchSQL nvarchar(MAX),
#CreatedByUser int
)
as
BEGIN
--get correct Sorted By
DECLARE #strSortedBy nvarchar(300)
SET #strSortedBy =
(CASE
WHEN (#SortedBy = 'CreatedDate') THEN 'Products.CreatedDate ' + #SortedIn
WHEN (#SortedBy = 'Views') THEN 'Products.Views ' + #SortedIn
ELSE 'Products.ProductName ' + #SortedIn
END)
--check if you are filtering by Category START
DECLARE #FilterByCategoryID nvarchar(250)
IF (#CategoryID > 0)
BEGIN
SET #FilterByCategoryID = 'AND Products.CategoryID = ' + cast(#CategoryID as nvarchar(5))
END
else
BEGIN
IF (#CategoryIDPath <> '') --show category features first then the most recent by default
BEGIN
SET #FilterByCategoryID = 'AND Products.CategoryIDPath LIKE ' + #CategoryIDPath
END
else
BEGIN
SET #FilterByCategoryID = ''
END
END
--check if you are filtering by Category END
--this option is used when you are searching by category only START
IF (#SearchText <> '')
BEGIN
IF #SearchSQL = 'ALL'
BEGIN
SET #SearchSQL = ''
END
END
else
BEGIN
SET #SearchSQL = ''
END
--this option is used when you are searching by category only END
--check if you are filtering by CreatedByUser START
DECLARE #FilterByCreatedByUser nvarchar(250)
IF (#CreatedByUser > 0)
BEGIN
SET #FilterByCreatedByUser = 'AND Products.CreatedByUser = ' + cast(#CreatedByUser as nvarchar(10))
END
else
BEGIN
SET #FilterByCreatedByUser = ''
END
--check if you are filtering by CreatedByUser END
DECLARE #MaximumRow int
SET #MaximumRow = #startRowIndex + #maximumRows
exec('SELECT
RowRank
,Products.ItemID
,Products.ProductName
,Products.Description
,Products.CategoryID
,Products.CategoryIDPath
,Products.FileName
,Products.CategoryName
,Businesses.BusinessName
,Businesses.Country
,Products.TotalCount
FROM
(
SELECT
ROW_NUMBER() OVER(ORDER BY ' + #strSortedBy + ') AS RowRank
,COUNT(*) OVER() AS TotalCount
,Products.*
FROM
Products
INNER JOIN Businesses
ON Products.CreatedByUser = Businesses.CreatedByUser
AND Businesses.Published <> 0
AND (Businesses.[ExpireDate] >= GetDate() or Businesses.[ExpireDate] is null)
WHERE
Products.Published <> 0
AND (Products.[ExpireDate] >= GetDate() OR Products.[ExpireDate] is null)
AND Products.ItemType = ''Classifieds''
' + #FilterByCategoryID + '
' + #FilterByCreatedByUser + '
' + #SearchSQL + '
) AS Products
INNER JOIN Businesses
ON Products.CreatedByUser = Businesses.CreatedByUser
AND Businesses.Published <> 0
AND (Businesses.[ExpireDate] >= GetDate() or Businesses.[ExpireDate] is null)
WHERE
RowRank > ' + #startRowIndex + ' AND RowRank <= ' + #MaximumRow + '
ORDER BY ' + #strSortedBy)
END
Solved it (hopefully!)
I have a user-defined table data type used as a parameter in a stored procedure.
I did a spy on it and it throws an error like the this:
A column cannot be of a user-defined table type.[16,1]{,1}
Is it not supported? If not, I am interested on how anyone did it - I mean spy a stored procedure similar to my case.
My db server is SQL2008 R2.
Below is the sample code to replicate it:
CREATE TYPE [dbo].[UserDefinedTableType] AS TABLE
(
[col1] INT NULL
,[col2] NVARCHAR(MAX) NULL
)
GO
CREATE PROCEDURE dbo.Bar
#ItemsToProcess UserDefinedTableType READONLY
AS
GO
CREATE PROCEDURE dbo.Foo
#ItemsToProcess UserDefinedTableType READONLY
AS
EXEC dbo.Bar #ItemsToProcess = #ItemsToProcess
GO
CREATE PROCEDURE [testDatabase].[test spy stored procedure using user-defined table type]
AS
DECLARE #items AS UserDefinedTableType
EXEC tSQLt.SpyProcedure 'dbo.Bar';
EXEC [dbo].[Foo] #ItemsToProcess = #items;
GO
EXEC tSQLt.Run '[testDatabase].[test spy stored procedure using user-defined table type]'
Hacked code below.
I've marked my changes. The goal was to query values from a table-valued parameter as XML. Note: The code is not yet thoroughly tested.
---Build+
CREATE PROCEDURE tSQLt.Private_CreateProcedureSpy
#ProcedureObjectId INT,
#OriginalProcedureName NVARCHAR(MAX),
#LogTableName NVARCHAR(MAX),
#CommandToExecute NVARCHAR(MAX) = NULL
AS
BEGIN
DECLARE #Cmd NVARCHAR(MAX);
DECLARE #ProcParmList NVARCHAR(MAX),
#TableColList NVARCHAR(MAX),
#ProcParmTypeList NVARCHAR(MAX),
#TableColTypeList NVARCHAR(MAX);
DECLARE #Seperator CHAR(1),
#ProcParmTypeListSeparater CHAR(1),
#ParamName sysname,
#TypeName sysname,
#IsOutput BIT,
/*>>>*/ #IsCursorRef BIT,
/*>>>*/ #IsTableType BIT;
SELECT #Seperator = '', #ProcParmTypeListSeparater = '',
#ProcParmList = '', #TableColList = '', #ProcParmTypeList = '', #TableColTypeList = '';
DECLARE Parameters CURSOR FOR
SELECT p.name, t.TypeName, is_output, is_cursor_ref, tp.is_table_type
FROM sys.parameters p CROSS APPLY tSQLt.Private_GetFullTypeName(p.user_type_id,p.max_length,p.precision,p.scale,NULL) t
/*>>>*/ INNER JOIN sys.types tp
/*>>>*/ ON p.user_type_id = tp.user_type_id
WHERE object_id = #ProcedureObjectId;
OPEN Parameters;
/*>>>*/ FETCH NEXT FROM Parameters INTO #ParamName, #TypeName, #IsOutput, #IsCursorRef, #IsTableType;
WHILE (##FETCH_STATUS = 0)
BEGIN
IF #IsCursorRef = 0
BEGIN
SELECT #ProcParmList = #ProcParmList + #Seperator +
CASE WHEN #IsTableType = 1
/*>>>*/ THEN '(SELECT * FROM ' + #ParamName + ' for xml path(''''))'
ELSE
#ParamName
END
,
#TableColList = #TableColList + #Seperator + '[' + STUFF(#ParamName,1,1,'') + ']',
#ProcParmTypeList = #ProcParmTypeList
+ #ProcParmTypeListSeparater
+ #ParamName
+ ' '
+ #TypeName
/*>>>*/ + CASE WHEN #IsTableType = 1 THEN ' READONLY ' ELSE ' = NULL ' END
+ CASE WHEN #IsOutput = 1 THEN ' OUT' ELSE '' END,
#TableColTypeList = #TableColTypeList + ',[' + STUFF(#ParamName,1,1,'') + '] ' +
/*>>>*/ CASE WHEN #IsTableType = 1 -- If parameter is a user-defined table type.
/*>>>*/ THEN 'xml'
WHEN #TypeName LIKE '%nchar%'
OR #TypeName LIKE '%nvarchar%'
THEN 'nvarchar(MAX)'
WHEN #TypeName LIKE '%char%'
THEN 'varchar(MAX)'
ELSE #TypeName
END + ' NULL';
SELECT #Seperator = ',';
SELECT #ProcParmTypeListSeparater = ',';
END
ELSE
BEGIN
SELECT #ProcParmTypeList = #ProcParmTypeListSeparater + #ParamName + ' CURSOR VARYING OUTPUT';
SELECT #ProcParmTypeListSeparater = ',';
END;
/*>>>*/ FETCH NEXT FROM Parameters INTO #ParamName, #TypeName, #IsOutput, #IsCursorRef, #IsTableType;
END;
CLOSE Parameters;
DEALLOCATE Parameters;
DECLARE #InsertStmt NVARCHAR(MAX);
SELECT #InsertStmt = 'INSERT INTO ' + #LogTableName +
CASE WHEN #TableColList = '' THEN ' DEFAULT VALUES'
ELSE ' (' + #TableColList + ') SELECT ' + #ProcParmList
END + ';';
SELECT #Cmd = 'CREATE TABLE ' + #LogTableName + ' (_id_ int IDENTITY(1,1) PRIMARY KEY CLUSTERED ' + #TableColTypeList + ');';
EXEC(#Cmd);
SELECT #Cmd = 'CREATE PROCEDURE ' + #OriginalProcedureName + ' ' + #ProcParmTypeList +
' AS BEGIN ' +
#InsertStmt +
ISNULL(#CommandToExecute, '') + ';' +
' END;';
EXEC(#Cmd);
RETURN 0;
END;
---Build-
I have a large data set and i have to apply paging on that data set and after that the result set should be another data set. What is the reliable method to achieve that.
I have tried with 'PagedDataSource' class but i don't know how it is possible to convert to dataset or data table.
In my case i need a general solution. I have to bind to a control like gridview as well as i have to used it with normal html table.
check this article doing same thing you want : http://www.codeproject.com/KB/custom-controls/EnhanceGrid.aspx
following sp returns record that you want
CREATE PROCEDURE [dbo].[GetRequestedRecordByPage]
#FromList nvarchar(200) -- Table Name
,#SortingCol nvarchar(200) -- Sorting column Name
,#SelectList nvarchar(200) = '*' -- Select columns list
,#WhereClause nvarchar(200) = '' -- Where clause i.e condition
,#PageNum int = 1 -- Requested page number
,#PageSize int = 5 -- No of record in page
,#TotalNoOfRecord int output -- Total no of selected records
AS
Begin
SET NOCOUNT ON
DECLARE #Query nvarchar(max) -- query going to be execute
IF rtrim(ltrim(#WhereClause)) <> ''
BEGIN
SET #Query ='SELECT #TotalNoOfRecord = COUNT(*)
FROM ' + #FromList + '
WHERE ' + #WhereClause
END
ELSE
BEGIN
SET #Query ='SELECT #TotalNoOfRecord = COUNT(*)
FROM ' + #FromList
END
/* Count no. of record */
EXEC sp_executeSQL
#Query,
#params = N'#TotalNoOfRecord INT OUTPUT',
= #TotalNoOfRecord OUTPUT
DECLARE #lbound int, #ubound int
/* Calculating upper and lower bound */
SET #lbound = ((#PageNum - 1) * #PageSize)
SET #ubound = #lbound + #PageSize + 1
/* Get list of record(s) */
SELECT #Query = ''
SELECT #Query = 'SELECT *
FROM (
SELECT ROW_NUMBER() OVER(ORDER BY ' + #SortingCol + ') AS rownumber,' +#SelectList +
' FROM ' + #FromList
IF rtrim(ltrim(#WhereClause)) <> ''
BEGIN
SELECT #Query = #Query + ' WHERE ' + #WhereClause
END
SELECT #Query = #Query + ' ) AS tbl
WHERE rownumber > ' + CONVERT(varchar(9), #lbound) +
' AND rownumber < ' + CONVERT(varchar(9), #ubound)
EXEC (#Query)
End