Can I create a View of Function from a Temp Table - sql-server

Can I create a view or function using the below query? It uses temp tables. I am not able to create either a view or function.
--TEmp table--
IF OBJECT_ID('tempdb..#Enquiries') IS NOT NULL
DROP TABLE #Enquiries
GO
CREATE TABLE #Enquiries
(ID INT,PID INT,Name VARCHAR(50),Enquiries INT,EnquiryDate datetime)
INSERT INTO #Enquiries
SELECT ROW_NUMBER()
OVER (ORDER BY ProjectName) AS Row, (SELECT top 1 ITEM FROM DBO.split(e.InterestedProjects,',')) as Projects,P.ProjectName,COUNT(CAST(EnquiryDate AS DATE)) AS Enquiries,CAST(EnquiryDate AS DATE) AS EnquiryDate
FROM tbl_Enquiry e INNER JOIN
tbl_Projects AS P ON P.ProjectId = (SELECT TOP 1 ITEM FROM DBO.split(e.InterestedProjects,','))
WHERE e.IsActive=1 and e.isdeleted=0 AND p.IsActive=1 AND p.IsDeleted=0 AND P.ProjectId IN (SELECT TOP 1 ITEM FROM DBO.split(e.InterestedProjects,','))
GROUP BY e.InterestedProjects,P.ProjectName,CAST(EnquiryDate AS DATE)
--SiteVisits
IF OBJECT_ID('tempdb..#SiteVisit') IS NOT NULL
DROP TABLE #SiteVisit
GO
CREATE TABLE #SiteVisit
(ID INT,PID INT,Name VARCHAR(50),Sitevisits INT,PickUpDatetime datetime)
INSERT INTO #SiteVisit
SELECT ROW_NUMBER() OVER (ORDER BY ProjectName) AS Row,s.ProjectId,p.ProjectName As Name,count(sd.PickUpDatetime) AS Sitevisits,CAST(PickUpDatetime AS DATE) AS PickUpDatetime FROM tbl_SiteVisit s
INNER JOIN tbl_SiteVisitDetails sd ON s.SiteVisitId=sd.SiteVisitId
INNER JOIN tbl_Projects p ON p.ProjectId=s.ProjectId
WHERE s.IsActive=1 and s.isdeleted=0 AND sd.isactive=1 AND sd.isdeleted=0
GROUP BY s.ProjectId,sd.PickUpDatetime,p.ProjectName,CAST(PickUpDatetime AS DATE)
--Bookings
IF OBJECT_ID('tempdb..#Bookings') IS NOT NULL
DROP TABLE #Bookings
GO
CREATE TABLE #Bookings
(ID INT,PID INT,Name VARCHAR(50),Bookings INT,BookingDate datetime,Revenue money,Area float)
INSERT INTO #Bookings
SELECT ROW_NUMBER() OVER (ORDER BY ProjectName) AS Row, u.ProjectId AS ProjectId,p.ProjectName,count(u.ProjectId) AS Bookings,CAST(b.BookingDate AS DATE) AS BookingDate,SUM(b.TotalAmount) AS [Revenue],SUM(u.UnitArea) AS [Area] FROM tbl_Bookings b
INNER JOIN tbl_Unit u ON b.UnitId=u.UnitId
INNER JOIN tbl_Projects p on p.ProjectId=u.ProjectId
WHERE b.IsActive=1 AND b.IsDeleted=0 and u.IsActive=1 AND u.IsDeleted=0 AND u.Status = 'B'
GROUP BY u.ProjectId,p.ProjectName,CAST(b.BookingDate AS DATE),b.TotalAmount,u.UnitArea
--ORDER BY u.ProjectId
IF OBJECT_ID('tempdb..#T1') IS NOT NULL
DROP TABLE #T1
create TABLE #T1 (
PrimaryNo INT,
EnquiryDate Date,
Enquiries INT,
SiteVisits INT,
Bookings INT,
Revenue Money,
Area Float,
PID INT,
ProjectName nvarchar(max)
)
INSERT INTO #T1(PrimaryNo,EnquiryDate,Enquiries,PID,ProjectName)
SELECT ID,EnquiryDate,sum(enquiries) AS Enquiries,PID,Name FROM #Enquiries GROUP BY id,pid,Name,enquirydate
DECLARE #SVDate date
DECLARE #SV11 INT
DECLARE #BookingDate Date
DECLARE #Bookings11 INT
DECLARE #Revenue11 MONEY
DECLARE #Area11 FLOAT
DECLARE #intFlag_pw11 INT
SET #intFlag_pw11 = 1
DECLARE #TableCntw11 INT
DECLARE #Date Date
DECLARE Cur_SiteVisit CURSOR FAST_FORWARD FOR
SELECT PickUpDatetime FROM #SiteVisit
OPEN Cur_SiteVisit
FETCH NEXT FROM Cur_SiteVisit INTO #Date
DECLARE #ProjectId INT
DECLARE #Count INT = 1
WHILE ##FETCH_STATUS = 0
BEGIN
SET #ProjectId = (SELECT PID FROM #SiteVisit WHERE ID = #Count)
SET #SVDate = ISNULL((SELECT CAST(PickUpDatetime AS DATE) FROM #SiteVisit
WHERE CAST(PickUpDatetime AS DATE) = #Date AND PID = #ProjectId
GROUP BY PickUpDatetime),'-')
SET #SV11 = ISNULL((SELECT Sitevisits FROM #SiteVisit
WHERE CAST(PickUpDatetime AS DATE) = #Date AND PID = #ProjectId
GROUP BY Sitevisits),0)
EXEC ('UPDATE #T1 SET SiteVisits = ' + #SV11 + ' WHERE EnquiryDate = ' + ''''+ #SVDate +''' AND PID =' + #ProjectId)
FETCH NEXT FROM Cur_SiteVisit INTO #Date
SET #Count = #Count + 1
END
CLOSE Cur_SiteVisit
DEALLOCATE Cur_SiteVisit
--For Bookings
DECLARE #Date1 Date
DECLARE Cur_Bookings CURSOR FAST_FORWARD FOR
SELECT BookingDate FROM #Bookings
OPEN Cur_Bookings
FETCH NEXT FROM Cur_Bookings INTO #Date1
DECLARE #ProjectId1 INT
DECLARE #Count1 INT = 1
WHILE ##FETCH_STATUS = 0
BEGIN
SET #ProjectId1 = (SELECT PID FROM #Bookings WHERE ID = #Count1)
SET #Bookings11 = ISNULL((SELECT TOP 1 Bookings FROM #Bookings
WHERE CAST(BookingDate AS DATE) = #Date1 AND PID = #ProjectId1
GROUP BY Bookings),0)
SET #BookingDate = ISNULL((SELECT TOP 1 CAST(BookingDate AS DATE) FROM #Bookings
WHERE CAST(BookingDate AS DATE) = #Date1 AND PID = #ProjectId1
GROUP BY CAST(BookingDate AS DATE)),'-')
SET #Revenue11 = ISNULL((SELECT TOP 1 Revenue FROM #Bookings
WHERE CAST(BookingDate AS DATE) = #Date1 AND PID = #ProjectId1
GROUP BY Revenue),0)
SET #Area11 = ISNULL((SELECT TOP 1 Area FROM #Bookings
WHERE CAST(BookingDate AS DATE) = #Date1 AND PID = #ProjectId1
GROUP BY Area),0)
EXEC ('UPDATE #T1 SET Bookings = ' + #Bookings11 + ',Revenue=' + #Revenue11 + ',Area = ' + #Area11 + ' WHERE EnquiryDate = ' + '''' + #BookingDate + ''' AND PID =' + #ProjectId1)
FETCH NEXT FROM Cur_Bookings INTO #Date1
SET #Count1 = #Count1 + 1
END
CLOSE Cur_Bookings
DEALLOCATE Cur_Bookings
Select * from #T1

You can't create a view from that, if only because you're doing a number of inserts and other actions. A view is created from a single query.
With regard to user-defined functions: you cannot use dynamic SQL, which you are doing:
EXEC ('UPDATE #T1 SET Bookings = ' + #Bookings11 + ',Revenue=' + #Revenue11 +
',Area = ' + #Area11 + ' WHERE EnquiryDate = ' + '''' + #BookingDate +
''' AND PID =' + #ProjectId1)
You also can't use temp tables. Both of these limitations are documented here: http://msdn.microsoft.com/en-us/library/ms191320.aspx.
But, you can do all of these things in a stored procedure. It is also possible to direct the output of a stored procedure to a temp table or table variable, allowing you to use the output in another query:
INSERT INTO dbo.MyTable
(MyTableId, Column1, Column2) -- arbitrary-chosen column names
EXEC dbo.MyStoredProcedure
SELECT *
FROM dbo.MyTable
WHERE Column1 = 'Some Value'
Finally, you might be able to rework your SQL to work with table variables rather than temp tables, which are allowed. It also looked to me like your dynamic SQL didn't need to be dynamic, so you might be able to eliminate that as well.
Hope this helps.

Related

SQL - Iterate over a temp table to check for free DBs names

I'm trying to do an SQL script here but facing some dificulties as I don't have so much knowledges on that, here is my issue:
I need to create a temp table with pre-determined values (dbrsm01 to dbrsm30) and check iterating through these values if one of them is available on MSSQL server to be used as a new database, if one of these values is already in use it needs to be ignored as I need to create a new DB using this value.
Here is what I've done so far:
DECLARE #temp TABLE (id int, dbname varchar(10))
INSERT INTO #temp VALUES(1,'dbrsm01');
INSERT INTO #temp VALUES(2,'dbrsm02');
INSERT INTO #temp VALUES(3,'dbrsm03');
...
INSERT INTO #temp VALUES(27,'dbrsm27');
INSERT INTO #temp VALUES(28,'dbrsm28');
INSERT INTO #temp VALUES(29,'dbrsm29');
INSERT INTO #temp VALUES(30,'dbrsm30');
DECLARE #maxid INT, #counter INT, #tempname VARCHAR(10), #nameset VARCHAR(10)
SET #counter = 1
SELECT #maxid = COUNT(*) FROM #temp
WHILE (#counter <= #maxid OR #nameset = #tempname)
BEGIN
SET #tempname = (SELECT dbname FROM #temp WHERE id = #counter)
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = #tempname)
BEGIN
SET #nameset = #tempname
END
SET #counter = #counter + 1
END
SELECT #nameset as [#dbname]
Any help on that is appreciate! Thank you all!
This doesn't need to be iterative at all. You can do this in a single statement:
WITH Tally AS (
SELECT 1 AS i
UNION ALL
SELECT i + 1
FROM Tally
WHERE i + 1 <= 30)
SELECT 'dbrsm' + CONVERT(varchar(7),T.i)
FROM Tally T
LEFT JOIN sys.databases d ON 'dbrsm' + CONVERT(varchar(7),T.i) = d.[name]
WHERE d.database_id IS NULL;
Edit: A mindset you need to change when writing SQL is thinking programmatically. You don't want to think about what you're going to do to a row, you need to think about what you're going to do to a column. Using loops are not a way of thinking in a dataset approach (normally).
Edit: Nevermind, here's how to make a CREATE statement and make all the databases:
DECLARE #SQL nvarchar(MAX);
WITH Tally AS (
SELECT 1 AS i
UNION ALL
SELECT i + 1
FROM Tally
WHERE i + 1 <= 30)
SELECT #SQL = STUFF((SELECT NCHAR(10) + N'CREATE DATABASE ' + QUOTENAME(N'dbrsm' + CONVERT(varchar(7),T.i)) + N';'
FROM Tally T
LEFT JOIN sys.databases d ON 'dbrsm' + CONVERT(varchar(7),T.i) = d.[name]
WHERE d.database_id IS NULL
FOR XML PATH ('')),1,1,'');
PRINT #SQL; --This is your best friend for troubleshooting
--EXEC sp_executesql #SQL; --Uncomment to run your dynamic SQL
You could use dynamic SQL:
DECLARE #sql NVARCHAR(MAX)
,#maxid INT = (SELECT COUNT(*) FROM #temp)
,#counter INT = 1
,#tempname VARCHAR(10)
,#nameset VARCHAR(10);
WHILE (#counter <= #maxid)
BEGIN
SET #tempname = (SELECT dbname FROM #temp WHERE id = #counter);
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = #tempname)
BEGIN
SET #nameset = #tempname;
SET #sql = 'CREATE DATABASE ' + QUOTENAME(#nameset);
PRINT #sql;
EXEC (#sql);
END
SET #counter += 1;
END
You can use BREAK and do what you want, like this:
DECLARE #temp TABLE (id int, dbname varchar(10))
INSERT INTO #temp VALUES(1,'dbrsm01');
INSERT INTO #temp VALUES(2,'dbrsm02');
INSERT INTO #temp VALUES(3,'dbrsm03');
DECLARE #maxid INT, #counter INT, #tempname VARCHAR(10), #nameset VARCHAR(10)
SET #counter = 1
SELECT #maxid = COUNT(*) FROM #temp
WHILE (#counter <= #maxid /*OR #nameset = #tempname --YOU DON'T NEED THIS */)
BEGIN
SELECT #tempname = dbname FROM #temp WHERE id = #counter
PRINT #tempname
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = #tempname)
BEGIN
SET #nameset = #tempname
PRINT 'ITS FREE'
BREAK
END
ELSE
PRINT 'ITS IN USE!'
SET #counter = #counter + 1
END
SELECT #nameset as [#dbname]
If you need to create all DB's that dont exist, remove the BREAK and add your logic (CREATE DATABASE ...)
SELECT 'CREATE Database '+A.dbname+'
GO '
FROM
(
SELECT K.dbname
FROM #temp K
LEFT JOIN sys.databases Y
ON K.dbName = Y.Name
WHERE Y.name is NULL
)A
You can copy the result of this statement and run it.

How to add rows with null data dynamically in result table in SQL Server 2012?

I have this table with 22 rows as above
I am getting a converted table as above
I created following procedure in order to get result table
ALTER PROCEDURE [dbo].[proc_YS_BAB_IR_Item]
#UserId int
AS
BEGIN TRAN
DECLARE #SqlQry NVARCHAR(MAX);
SET #SqlQry = N''
DECLARE #Cnt INT = 1, #EndCnt INT = 25,
#v_UserId INT = CAST(#UserId AS VARCHAR(MAX));
CREATE TABLE #TempColumns
(
Calculate_ItemIdentifier VARCHAR(MAX),
SeqOrder INT
)
WHILE #cnt <= #EndCnt
BEGIN
INSERT INTO #TempColumns
SELECT
'IR'+ CAST(#Cnt AS VARCHAR(MAX)),
#Cnt
SET #Cnt = #Cnt + 1;
END
DECLARE #DATA VARCHAR(10), #DATA1 VARCHAR(10) = '000000'
DECLARE #zero_str VARCHAR(6) = '000000'
-- Generate table alike to yours
DECLARE #yourTable TABLE ([value] varchar(max))
-- convert array to xml
;WITH cte AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS rn,
[response],
CAST('<a>'+REPLACE(SUBSTRING([response],2,LEN([response]) - 2),',','</a><a>')+'</a>' as xml) AS x,
#v_UserId AS UserId,
[item_identifier]
FROM
#TempColumns
LEFT JOIN
YS_BAB_response_dump ON YS_BAB_response_dump.Item_Identifier = #TempColumns.Calculate_ItemIdentifier
AND UserId = CAST(#UserId AS VARCHAR(MAX))
AND TestModel = 'IR'
)
-- do the stuff
SELECT
c.rn,
c.[response],
c.[item_identifier],
RIGHT(#zero_str +
CAST(SUM(CAST(STUFF(#zero_str,t.c.value('.','tinyint')+1,1,'1') AS INT)) AS VARCHAR(6)), 6) AS ans,
c.UserId
FROM
cte c
CROSS APPLY
x.nodes('/a') AS t(c)
GROUP BY
c.rn, c.[response], c.UserId, c.[Item_Identifier]
ORDER BY
c.rn
COMMIT TRAN
What changes I need to do in above procedure to get 25 records as a result instead of 22, For IR21,IR22 and IR25 I want null data in response and ans columns for that respective userId? May i need to use some other function instead of CROSS APPLY? How it will be?
You were almost there. Use OUTER APPLY instead of CROSS APPLY

Add columns dynamically and Later Parse values in the respective columns

I have an SP which accepts the Inputtable as parameter, My Inputtable is as shown in the code
`create table inputTable ( id int,ItemQty varchar(100))
insert into inputTable(id, ItemQty) values(1,'a,b,c')
insert into inputTable(id, ItemQty) values(2,'x,y')
insert into inputTable(id, ItemQty) values(3,'l,m,n,o,p')
insert into inputTable(id, ItemQty) values(4,'a,b')
insert into inputTable(id, ItemQty) values(5,'m')`
and SP i have written is like below
`ALTER PROCEDURE [dbo].[Column_Dynamics] (#tablename varchar(50))
AS
BEGIN
-----
declare #maxcount as int
set #maxcount='select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename
exec('select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename)
print #maxcount
exec #maxcount
print #maxcount
declare #var varchar(100)
IF EXISTS(SELECT * FROM sys.columns WHERE object_id = Object_id(#tablename))
set #var='alter table '+ #tablename +' ADD column QTY1'
exec(#var)
select * from #tablename
select max(len(ItemQty))-max(len(replace(ItemQty, ',', ''))-1) from inputtable
END`
My table is :
step 1 ) I want to add the columns dynamically to inputtable like QTY1,QTY2,QTY3,QTY4,QTY5 because maximum count of ItemQty column is 5, by considering comma as delimiter as shown in figure1
**step 2) ** Parse values in the respective columns(by considering the delimiter comma (,).as shown in figure2
Later SP: I got till here, But Not getting the second step, that is update Parse values in the respective columns.
ALTER PROCEDURE dynamic_tbl (#tablename varchar(50))
AS
BEGIN
DECLARE #ColumnCount int
DECLARE #rowcount TABLE (Value int);
INSERT INTO #rowcount
EXEC('select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename);
SELECT #ColumnCount = Value FROM #rowcount;
Declare #ColumnName nvarchar(10)='qty_'
Declare #count int =0
IF(#ColumnCount>0)
BEGIN
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'dyn_tbl'))
BEGIN
DROP TABLE dyn_tbl
END
select * into dyn_tbl from inputtable
SET #count=#count +1;
WHile(#ColumnCount>=#count)
BEGIN
SET #ColumnName='qty_'+CONVERT(varchar(2),#count)
EXEC ('ALTER TABLE dyn_tbl ADD ['+#ColumnName +'] varchar(20)')
declare #myvar as varchar(max)
set #myvar='update '+#tablename+' set '+#ColumnName +' =itemQty'
--exec dynamic_tbl 'dyn_tbl'
--select * from dyn_tbl
--CAST('<A>'+REPLACE(ITEMQTY, ',', '</A><A>')+'</A>' AS XML)
print #myvar
exec(#myvar)
SET #count=#count +1;
END
END
----
END
Procedure to alter given table dynamically based on column length as you have asked
Alter PROCEDURE [dbo].[Column_Dynamics] (#tablename varchar(50))
AS
BEGIN
drop table ##temp
declare #query1 varchar(max)
exec ( '
create table ##temp (id int identity,columnsl varchar(100))
declare #maxcount as int
set #maxcount = (select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename+')
declare #count int = 1
while (#count <= #maxcount)
begin
declare #colvar nvarchar(100)= ''QTY''
set #colvar = concat(#colvar,#count)
set #count = #count + 1
insert into ##temp select #colvar
end
')
declare #tempstart int = 1
declare #templast int = (select count(*) from ##temp)
declare #updatecol varchar(100) = ''
while (#tempstart <= #templast)
Begin
set #updatecol = (select columnsl from ##temp where id = #tempstart)
exec ('alter table '+#tablename+' Add '+#updatecol+' varchar(100) ')
set #tempstart = #tempstart + 1
end
End
output for inputTable:
id ItemQty QTY1 QTY2 QTY3 QTY4 QTY5
1 a,b,c NULL NULL NULL NULL NULL
2 x,y NULL NULL NULL NULL NULL
3 l,m,n,o,p NULL NULL NULL NULL NULL
4 a,b NULL NULL NULL NULL NULL
5 m NULL NULL NULL NULL NULL
may not be the best way but works.
edit
Altered above procedure to perform both actions, Please use below procedure
Alter PROCEDURE [dbo].[Column_Dynamics] (#tablename varchar(50))
AS
BEGIN
-- declare #tablename varchar(100) = 'inputTable'
drop table #temp if object_id('temp..#temp') is not null drop table #temp
declare #query1 varchar(max)
create table #temp (id int identity,columnsl varchar(100))
exec ( '
declare #maxcount as int
set #maxcount = (select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename+')
declare #count int = 1
while (#count <= #maxcount)
begin
declare #colvar nvarchar(100)= ''QTY''
set #colvar = concat(#colvar,#count)
set #count = #count + 1
insert into #temp
select #colvar
end
')
declare #tempstart int = 1
declare #templast int = (select count(*) from #temp)
declare #updatecol varchar(100) = ''
declare #itemqty varchar(100)
while (#tempstart <= #templast)
Begin
set #updatecol = (select columnsl from #temp where id = #tempstart)
exec ('alter table '+#tablename+' Add '+#updatecol+' varchar(100) ')
set #tempstart = #tempstart + 1
end
declare #sysvar table (id int identity,cols varchar(100))
insert into #sysvar select sys.columns.name AS ColumnName FROM sys.columns JOIN sys.tables ON sys.columns.object_id = sys.tables.object_id WHERE sys.tables.name = 'inputTable'
declare #finvar table (id int identity,cols varchar(100))
insert into #finvar select cols from #sysvar where id not in (1,2)
declare #cat int = 1 declare #dog int = (select max(id) from inputTable)
while (#cat <= #dog)
begin
drop table #tab2
if object_id('temp..#tab2') is not null drop table #tab2
create table #tab2 (id int identity,fnvalues varchar(100))
set #itemqty = (select itemqty from inputTable where id = #cat)
insert into #tab2 select item from [dbo].[fnSplit](#itemQty,',')
declare #cn int = 1
declare #max int = (select max(id) from #tab2)
declare #sql nvarchar (1000);
while (#cn <= #max)
begin
declare #upcol varchar(100) = (select fnvalues from #tab2 where id = #cn)
declare #plscol varchar(100) = (select cols from #finvar where id = #cn)
set #sql = N'update '+#tablename+' set ' + #plscol + '= '''+#upcol+''' where id = '''+cast(#cat as varchar(10))+''' ';
select #sql
exec sp_executesql #sql;
set #cn = #cn + 1
end
set #cat = #cat + 1
End
End
output:
id ItemQty QTY1 QTY2 QTY3 QTY4 QTY5
1 a,b,c a b c NULL NULL
2 x,y x y NULL NULL NULL
3 l,m,n,o,p l m n o p
4 a,b a b NULL NULL NULL
5 m m NULL NULL NULL NULL
did not optimize the query but works fine.
However, if you have maximum Qty's are known which are in comma separated format then you could use xml node method to separate them into columns.QTY1...QTY5
SELECT DISTINCT ID, ITEMQTY,
a.value('/A[1]', 'VARCHAR(MAX)') as QTY1,
a.value('/A[2]', 'VARCHAR(MAX)') as QTY2,
a.value('/A[3]', 'VARCHAR(MAX)') as QTY3,
a.value('/A[4]', 'VARCHAR(MAX)') as QTY4,
a.value('/A[5]', 'VARCHAR(MAX)') as QTY5
FROM
(
SELECT ID, ITEMQTY,
CAST('<A>'+REPLACE(ITEMQTY, ',', '</A><A>')+'</A>' AS XML) AS ITEMQTY1
FROM inputTable
) A
CROSS APPLY ITEMQTY1.nodes('/A') AS split(a);
Result :
ID ITEMQTY QTY1 QTY2 QTY3 QTY4 QTY5
1 a,b,c a b c NULL NULL
2 x,y x y NULL NULL NULL
3 l,m,n,o,p l m n o p
4 a,b a b NULL NULL NULL
5 m m NULL NULL NULL NULL
Later, you could replace null by using coalesce() or isnull() function with ''
Use This
First Create a function
CREATE FUNCTION [dbo].[fn_split](
#str VARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #returnTable TABLE (idx INT PRIMARY KEY IDENTITY, item VARCHAR(8000))
AS
BEGIN
DECLARE #pos INT
SELECT #str = #str + #delimiter
WHILE LEN(#str) > 0
BEGIN
SELECT #pos = CHARINDEX(#delimiter,#str)
IF #pos = 1
INSERT #returnTable (item)
VALUES (NULL)
ELSE
INSERT #returnTable (item)
VALUES (SUBSTRING(#str, 1, #pos-1))
SELECT #str = SUBSTRING(#str, #pos+1, LEN(#str)-#pos)
END
RETURN
END
GO
and use function like this
Declare #test TABLE (
ID VARCHAR(200),
Data VARCHAR(200)
)
insert into #test
(ID, Data)
Values
(1,'a,b,c')
insert into #test
(ID, Data )
values(2,'x,y')
insert into #test
(ID, Data )
values(3,'l,m,n,o,p')
insert into #test
(ID, Data )
values(4,'a,b')
insert into #test
(ID, Data )
values(5,'m')
select ID,data AS ItemQty,
ISNULL((select item from fn_split(Data,',') where idx in (1)),'') as QTY1 ,
ISNULL((select item from fn_split(Data,',') where idx in (2)),'') as QTY2,
ISNULL((select item from fn_split(Data,',') where idx in (3)),'') as QTY3,
ISNULL((select item from fn_split(Data,',') where idx in (4)),'') as QTY5 ,
ISNULL((select item from fn_split(Data,',') where idx in (5)),'') as QTY5
from #test
Output Same as your Image
instead of using
insert into #test
(ID, Data)
Values
(1,'a,b,c')
you can also assgin it like this
insert into #test
(ID, Data)
Values
(Select Column1, Column2 From YourTable)

What is the right way to count number of records returned by group by query

How do I count the number of actual records returned by a group by query
For e.g
-- Exec SP_GET_ITEM_STOCK 0,10,NULL,'Charger'
ALTER PROCEDURE [dbo].[SP_GET_ITEM_STOCK]
#startRowIndex int ,
#pageSize int,
#ItemID bigint = null,
#ItemName varchar(250) = null
AS
BEGIN
DECLARE #SQL varchar(MAX)
DECLARE #SQLWHERE varchar(MAX)
SET #SQL = 'WITH DATA AS (
select
ROW_NUMBER() OVER (ORDER BY Item_ID) ''SNo'',
Item_ID,
Item_Name,
SUM(Inward) as Total_Purchase,
SUM(Outward) as Total_Sale,
(sum(Inward) - sum(outward))as Balance_Stock'
Set #SQLWHERE = ' from Item_Ledger_Details where Active = 1'
IF #ItemID IS NOT NULL and #ItemID <> ''
SET #SQLWHERE = #SQLWHERE + ' and Item_ID = ' + CONVERT(varchar,#ItemID) + ''
IF #ItemName IS NOT NULL and #ItemName <> ''
SET #SQLWHERE = #SQLWHERE + ' and Item_Name like ''%' + #ItemName + '%'''
SET #SQL = #SQL + #SQLWHERE + ' group by Item_ID,Item_Name) SELECT * FROM DATA WHERE SNo BETWEEN ' + CONVERT(Varchar,#startRowIndex) + ' AND ' + CONVERT(Varchar,#startRowIndex+#pageSize) + ' ORDER BY SNo'
EXEC(#SQL +';SELECT COUNT(*) ''Count'' '+ #SQLWHERE)
print(#SQL)
END
Which returns:
I need to count the above first result records to get 1 + 1 = 2 in second result where I get count = 48
Continue Anand Answer. I've just modify his query. Below query is solved my answer. But I think may be this query needs optimization.
-- SP_GET_ITEM_STOCK 0,10,NULL,NULL
ALTER PROCEDURE [dbo].[SP_GET_ITEM_STOCK]
#startRowIndex int,
#pageSize int,
#ItemID bigint = null,
#ItemName varchar(250) = null
AS
BEGIN
Declare #Temp Table (
SNo bigint,
Item_ID bigint,
Item_Name varchar(max),
Total_Purchase money,
Total_Sale money,
Balance_Stock money
);
WITH DATA AS (
select
ROW_NUMBER() OVER (ORDER BY Item_ID) as SNo,
Item_ID,
Item_Name,
SUM(Inward) as Total_Purchase,
SUM(Outward) as Total_Sale,
(sum(Inward) - sum(outward))as Balance_Stock
from Item_Ledger_Details
where Active = 1
and (coalesce(#ItemID, '') = '' or Item_ID = CONVERT(varchar,#ItemID))
and ( coalesce(#ItemName, '') = '' or Item_Name like '%' + #ItemName + '%')
group by Item_ID,
Item_Name
)
insert into #Temp
SELECT *
FROM DATA
WHERE SNo BETWEEN #startRowIndex AND #startRowIndex+#pageSize
ORDER BY SNo
select * from #temp
SELECT COUNT(*) as Count from #temp
END
There, I've cleaned it up:
ALTER PROCEDURE [dbo].[SP_GET_ITEM_STOCK]
#startRowIndex int,
#pageSize int,
#ItemID bigint = null,
#ItemName varchar(250) = null
AS
BEGIN
;WITH DATA AS (
select
ROW_NUMBER() OVER (ORDER BY Item_ID) as SNo,
Item_ID,
Item_Name,
SUM(Inward) as Total_Purchase,
SUM(Outward) as Total_Sale,
(sum(Inward) - sum(outward))as Balance_Stock
from Item_Ledger_Details
where Active = 1
and (coalesce(#ItemID, '') = '' or Item_ID = CONVERT(varchar,#ItemID))
and ( coalesce(#ItemName, '') = '' or Item_Name like '%' + #ItemName + '%')
group by Item_ID,
Item_Name
)
SELECT *
FROM DATA
WHERE SNo BETWEEN #startRowIndex AND #startRowIndex+#pageSize
ORDER BY SNo
SELECT COUNT(*) as Count
from DATA
END

Invalid column name '#Results'

alter PROCEDURE sp_Get_CustInfoSerach2
(#PageIndex INT = 1
,#PageSize INT = 10
,#RecordCount INT OUTPUT
,#ColumnName VARCHAR(50)=null
,#Value VARCHAR(50)=null
,#ddlValue VARCHAR(50)=null
,#txtValue VARCHAR(50)=null
,#status varchar(30))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cmd AS NVARCHAR(max)
if #txtValue IS NULL
Begin
SET #Value = ''''+#ddlValue+ ''''
End
else if #ddlValue IS NULL
begin
SET #Value = ''''+#txtValue+ ''''
end
SET #cmd = 'SELECT ROW_NUMBER() OVER
(
ORDER BY C_Register.UserId desc
)AS RowNumber
,C_Register.UserId, C_Register.Name, C_Register.UserName, C_Register.Status,
Packages.PackagePeriod, Packages.PackageName, C_Register.ActivationDate,
Receive_Payment.OldExpiryDate, Receive_Payment.Balance, Receive_Payment.PyingAmount,
Receive_Payment.LastPaidDate, C_Register.LastUpdateTime,
Area.AreaName, C_Register.MobNo, Employee.EmpName, C_Register.Address,C_Register.CreatedDate
INTO'+ #Results+'
FROM C_Register INNER JOIN Receive_Payment ON C_Register.UserId = Receive_Payment.UserId
INNER JOIN Area ON C_Register.AreaId = Area.AreaId
INNER JOIN Employee ON Receive_Payment.EmpId = Employee.EmpId
INNER JOIN Packages ON Receive_Payment.PackageId = Packages.PackageId
where C_Register.AccountExpiry= Receive_Payment.OldExpiryDate And C_Register.Status = '+#status+'And
' + #ColumnName + ' = ' + #Value
SELECT #RecordCount = COUNT(*)
FROM #Results
SELECT * FROM #Results
WHERE RowNumber BETWEEN(#PageIndex -1) * #PageSize + 1 AND(((#PageIndex -1) * #PageSize + 1) + #PageSize) - 1
DROP TABLE #Results
EXEC(#cmd)
END
throwing error:
Invalid column name '#Results'.
how to solve it?
If i understand your problem correctly you should first exec dynamic sql before select from temporary table
Alter PROCEDURE sp_Get_CustInfoSerach2
(
#PageIndex INT = 1 ,
#PageSize INT = 10 ,
#RecordCount INT OUTPUT ,
#ColumnName VARCHAR(50)=null ,
#Value VARCHAR(50)=null ,
#ddlValue VARCHAR(50)=null ,
#txtValue VARCHAR(50)=null ,
#status varchar(30)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cmd AS NVARCHAR(max)
If #txtValue IS NULL
Begin
SET #Value = ''''+#ddlValue+ ''''
End
Else
if #ddlValue IS NULL
Begin
SET #Value = ''''+#txtValue+ ''''
End
SET #cmd = 'SELECT ROW_NUMBER() OVER ( ORDER BY C_Register.UserId desc )AS RowNumber,
C_Register.UserId, C_Register.Name, C_Register.UserName, C_Register.Status,
Packages.PackagePeriod, Packages.PackageName, C_Register.ActivationDate,
Receive_Payment.OldExpiryDate, Receive_Payment.Balance, Receive_Payment.PyingAmount,
Receive_Payment.LastPaidDate, C_Register.LastUpdateTime,
Area.AreaName, C_Register.MobNo, Employee.EmpName, C_Register.Address,C_Register.CreatedDate
INTO #Results
FROM C_Register INNER JOIN Receive_Payment ON C_Register.UserId = Receive_Payment.UserId
INNER JOIN Area ON C_Register.AreaId = Area.AreaId
INNER JOIN Employee ON Receive_Payment.EmpId = Employee.EmpId
INNER JOIN Packages ON Receive_Payment.PackageId = Packages.PackageId
where C_Register.AccountExpiry= Receive_Payment.OldExpiryDate And C_Register.Status = '+#status+'And
' + #ColumnName + ' = ' + #Value
/*First Execute above dynamic Sql query */
EXEC(#cmd)
/* From the above execute statemnet the query will executed and temporary table will created on the fly */
SELECT #RecordCount = COUNT(*)
FROM #Results
SELECT * FROM #Results
WHERE RowNumber BETWEEN(#PageIndex -1) * #PageSize + 1 AND(((#PageIndex -1) * #PageSize + 1) + #PageSize) - 1
DROP TABLE #Results
Problem in your query is creation of temp table thats not right way to create temp table inside dynamic query.
But even if you create temp table inside a dynamic query it can be accessed only inside the session of dynamic query. If you try to select the temp outside of dynamic query which is created inside the dynamic query you will get a error saying object doesnot exist.
Since you know the number of columns present in the result of dynamic query you can create the temp table outside of dynamic query and insert the records through dynamic query.
Try changing your procedure like this.
ALTER PROCEDURE Sp_get_custinfoserach2 (#PageIndex INT = 1,
#PageSize INT = 10,
#RecordCount INT output,
#ColumnName VARCHAR(50)=NULL,
#Value VARCHAR(50)=NULL,
#ddlValue VARCHAR(50)=NULL,
#txtValue VARCHAR(50)=NULL,
#status VARCHAR(30))
AS
BEGIN
SET nocount ON;
DECLARE #cmd AS NVARCHAR(max)
IF #txtValue IS NULL
BEGIN
SET #Value = '''' + #ddlValue + ''''
END
ELSE IF #ddlValue IS NULL
BEGIN
SET #Value = '''' + #txtValue + ''''
END
/*create a temp as same structure of your dynamic query select statement*/
CREATE TABLE #result
(
rownum INT,
userid INT,
NAME VARCHAR(100),
username VARCHAR(100),
status VARCHAR(15),
packageperiod VARCHAR(15),
packagename VARCHAR(100),
activationdate DATETIME,
oldexpirydate DATETIME,
balance NUMERIC(22, 4),
pyingamount NUMERIC(22, 4),
lastpaiddate DATETIME,
lastupdatetime DATETIME,
areaname VARCHAR(100),
mobno INT,
empname VARCHAR(100),
address VARCHAR(5000),
createddate DATETIME
)
SET #cmd =
' Insert into #result
SELECT ROW_NUMBER() OVER (ORDER BY C_Register.UserId desc )AS RowNumber,
C_Register.UserId, C_Register.Name, C_Register.UserName,
C_Register.Status, Packages.PackagePeriod, Packages.PackageName,
C_Register.ActivationDate,Receive_Payment.OldExpiryDate,
Receive_Payment.Balance, Receive_Payment.PyingAmount,
Receive_Payment.LastPaidDate, C_Register.LastUpdateTime,
Area.AreaName, C_Register.MobNo, Employee.EmpName,
C_Register.Address,C_Register.CreatedDate
FROM C_Register
INNER JOIN Receive_Payment
ON C_Register.UserId = Receive_Payment.UserId
INNER JOIN Area
ON C_Register.AreaId = Area.AreaId
INNER JOIN Employee
ON Receive_Payment.EmpId = Employee.EmpId
INNER JOIN Packages
ON Receive_Payment.PackageId = Packages.PackageId
where C_Register.AccountExpiry= Receive_Payment.OldExpiryDate And C_Register.Status = ' + #status + ' And ' + #ColumnName + ' = ' + #Value
SELECT #RecordCount = Count(*)
FROM #results
SELECT *
FROM #results
WHERE rownumber BETWEEN( #PageIndex - 1 ) * #PageSize + 1 AND( (
( #PageIndex - 1 ) * #PageSize + 1 ) +
#PageSize ) - 1
DROP TABLE #results
EXEC(#cmd)
END
Note : I have given generic datatypes to temp table columns please change the datetypes according to your schema.

Resources