Use IN operator in THEN Statement in SQL - sql-server

I am writing a SQL statement which will get the information from table valued parameter based on the input given in stored procedure. The condition should work if the input value row count greater than zero. Please guide me with the below query.
DECLARE #DivisionIds [dbo].[IDList]
DECLARE #StateIds [dbo].[IDList]
INSERT INTO #DivisionIds Values (1)
INSERT INTO #DivisionIds Values (1)
INSERT INTO #StateIds Values (1)
INSERT INTO #StateIds Values (3)
INSERT INTO #StateIds Values (31)
INSERT INTO #StateIds Values (43)
SET #DivsionRowCount = (SELECT COUNT(ID) FROM #DivisionIds)
SET #StateRowCount = (SELECT COUNT(ID) FROM #StateIds)
SELECT * FROM MedInv inv INNER JOIN Location loc ON inv.MedInvID = loc.MedInvID
WHERE CustomerID = 210
AND
#DivsionRowCount > 0 AND loc.DivisionID IN (SELECT ID FROM #DivisionIds)
AND
#StateRowCount > 0 AND loc.StateID IN (SELECT ID FROM #StateIds)
The above code works fine, if I provide value for #DivisionIds and #StateIds. In some scenario #DivisionIds and StateIds does not have any values. So row count will be zero. I want to run the above condition only if the row count is greater than zero. How to do that?
My actual code contains the CASE statement for other conditions, I want to include the above condition in CASE statement, I tried the below approach but I am getting error.
DECLARE #DivisionIds [dbo].[IDList]
DECLARE #StateIds [dbo].[IDList]
SET #DivsionRowCount = (SELECT COUNT(ID) FROM #DivisionIds)
SET #StateRowCount = (SELECT COUNT(ID) FROM #StateIds)
SELECT CustomerName, InvEstValue, Status FROM MedInv inv
INNER JOIN Location loc ON loc.MedInvID = inv.MedInvID
INNER JOIN Division div ON div.DivisionID = loc.DivisionID
INNER JOIN State st ON st.StateID = loc.StateID
WHERE inv.CustomerID = 210
AND
inv.CustomerName Like
CASE WHEN #CustomerName = '' THEN '%%' ELSE '%' + #CustomerName + '%' END
AND
inv.AssetDescription Like
CASE WHEN #AssetDescription = '' THEN '%%' ELSE '%' + #AssetDescription + '%' END
AND
#DivsionRowCount > 0 AND loc.DivisionID IN (SELECT ID FROM #DivisionIds)
AND
#StateRowCount > 0 AND loc.StateID IN (SELECT ID FROM #StateIds)
AND
loc.DivisionID =
CASE WHEN (#DivsionRowCount > 0) THEN loc.DivisionID IN (SELECT ID FROM #DivisionIds) ELSE loc.DivisionID END
from the above, I am getting error near to IN and ELSE keywords saying that Incorrect Syntax near IN, Incorrect syntax near ELSE . Expecting END OR THEN.
Please guide me how to use IN operator in THEN statement.
I am expecting the condition should run only if the input value parameter count is greater than zero.

I'm not sure that you take the right approach with you case when in your condition but
The problem is that you with your last condition you'll have something like :
loc.DivisionID = in(...)
And "= in" is incorrect syntax
Maybe you can add your condition directly in the join
INNER JOIN Division div ON loc.DivisionID IN (SELECT ID FROM #DivisionIds)
Is that what you expected ?
But I think that you need also to put these 2 conditions in the join
AND
#DivsionRowCount > 0 AND loc.DivisionID IN (SELECT ID FROM #DivisionIds)
AND
#StateRowCount > 0 AND loc.StateID IN (SELECT ID FROM #StateIds)

Here's how I would write it:
DECLARE #DivisionIds [dbo].[IDList]
DECLARE #StateIds [dbo].[IDList]
SET #DivsionRowCount = (SELECT COUNT(ID) FROM #DivisionIds)
SET #StateRowCount = (SELECT COUNT(ID) FROM #StateIds)
SELECT CustomerName, InvEstValue, Status
FROM MedInv inv
INNER JOIN Location loc
ON loc.MedInvID = inv.MedInvID
INNER JOIN Division div
ON div.DivisionID = loc.DivisionID
INNER JOIN State st
ON st.StateID = loc.StateID
WHERE inv.CustomerID = 210
AND (#CustomerName = '' OR inv.CustomerName Like '%' + #CustomerName + '%')
AND (#AssetDescription = '' OR inv.AssetDescription LIKE '%' + #AssetDescription + '%')
AND (#DivsionRowCount = 0 OR loc.DivisionID IN (SELECT ID FROM #DivisionIds))
AND (#StateRowCount = 0 OR loc.StateID IN (SELECT ID FROM #StateIds))
You might want to add option(recompile) if you get performance problems.
Check out revisiting catch-all queries on SQL in the wild blog for details.

Related

Is it always possible to transform multiple spatial selects with while loop and variables into a single query without using temp tables in sql?

This problem can be solved with temp table, however, I don't want to use Temp table or var table, this question is mostly for my personal educational purposes.
I inherited the following SQL:
DECLARE #i int = 993
while #i <=1000
begin
declare #lat nvarchar(20)
select top 1 #lat = SUBSTRING(Address,0,CHARINDEX(',',Address,0)) from dbo.rent
where id = #i;
declare #lon nvarchar(20)
select top 1 #lon = SUBSTRING(Address,CHARINDEX(',',Address)+1,LEN(Address)) from dbo.rent
where id = #i
declare #p GEOGRAPHY = GEOGRAPHY::STGeomFromText('POINT('+ #lat +' '+#lon+')', 4326)
select price/LivingArea sq_m, (price/LivingArea)/avg_sq_m, * from
(select (sum(price)/sum(LivingArea)) avg_sq_m, count(1) cnt, #i id from
(select *, GEOGRAPHY::STGeomFromText('POINT('+
convert(nvarchar(20), SUBSTRING(Address,0,CHARINDEX(',',Address,0)))+' '+
convert( nvarchar(20), SUBSTRING(Address,CHARINDEX(',',Address)+1,LEN(Address)))+')', 4326)
.STBuffer(500).STIntersects(#p) as [Intersects]
from dbo.rent
where Address is not null
) s
where [Intersects] = 1) prox
inner join dbo.rent r on prox.id = r.id
set #i = #i+1
end
it is used to analyze property prices per square meter that are in proximity and compare them to see which ones are cheaper...
Problem: a mechanism for calling has to be moved from C# to SQL and all queries have to be combined into a single result (now you get one row per one while run), i.e #i and #p has to go and become while id < x and id > y or somehow magically joined,
the procedure is a cut down version of actual thing but having a solution to the above I will have no problem making the whole thing work...
I am of the opinion that any SQL mechanism with variables and loops can be transformed to a single SQL statement, hence the question.
SqlFiddle
If I understand your question properly (Remove the need for loops and return one data set) then you can use CTE (Common Table Expressions) for the Lats, Lons and Geog variables.
You;re SQLFIddle was referencing a database called "webanalyser" so I removed that from the query below
However, the query will not return anything as the sample data has wrong data for address column.
;WITH cteLatsLongs
AS(
SELECT
lat = SUBSTRING(Address, 0, CHARINDEX(',', Address, 0))
,lon = SUBSTRING(Address, CHARINDEX(',', Address) + 1, LEN(Address))
FROM dbo.rent
)
,cteGeogs
AS(
SELECT
Geog = GEOGRAPHY ::STGeomFromText('POINT(' + LL.lat + ' ' + LL.lon + ')', 4326)
FROM cteLatsLongs LL
),cteIntersects
AS(
SELECT *,
GEOGRAPHY::STGeomFromText('POINT(' + CONVERT(NVARCHAR(20), SUBSTRING(Address, 0, CHARINDEX(',', Address, 0))) + ' ' + CONVERT(NVARCHAR(20), SUBSTRING(Address, CHARINDEX(',', Address) + 1, LEN(Address))) + ')', 4326).STBuffer(500).STIntersects(G.Geog) AS [Intersects]
FROM dbo.rent
CROSS APPLY cteGeogs G
)
SELECT avg_sq_m = (SUM(price) / SUM(LivingArea)), COUNT(1) cnt
FROM
cteIntersects I
WHERE I.[Intersects] = 1
It can be done, in this specific case 'discovery' that was necessary was the ability to perform JOINs on Point e.g ability to join tables on proximity (another a small cheat was to aggregate point-strings to actual points, but it's just an optimization). Once this is done, a query could be rewritten as follows:
SELECT adds.Url,
adds.Price/adds.LivingArea Sqm,
(adds.Price/adds.LivingArea)/k1.sale1Avg ratio,
*
FROM
(SELECT baseid,
count(k1Rent.rentid) rent1kCount,
sum(k1Rent.RperSqM)/(count(k1Rent.rentid)) AS rent1kAvgSqM,
count(around1k.SaleId) sale1kCount,
(sum(k1sale.price)/sum(k1Sale.LivingArea)) sale1Avg,
(sum(k1sale.price)/sum(k1Sale.LivingArea))/((sum(k1Rent.RperSqM)/(count(k1Rent.rentid)))*12) years --*
FROM
(SELECT sa.id baseid,
s.id saleid,
s.RoomCount,
POINT
FROM SpatialAnalysis sa
INNER JOIN Sale s ON s.Id = SaleId
WHERE sa.SalesIn1kRadiusCount IS NULL) AS base
JOIN SpatialAnalysis around1k ON base.Point.STBuffer(1000).STIntersects(around1k.Point) = 1
LEFT OUTER JOIN
(SELECT id rentid,
rc,
Price/avgRoomSize RperSqM
FROM
(SELECT *
FROM
(SELECT rc,
sum(avgArea*c)/sum(c) avgRoomSize
FROM
(SELECT roomcount rc,
avg(livingarea) avgArea,
count(1) c
FROM Rent
WHERE url LIKE '%systemname%'
AND LivingArea IS NOT NULL
GROUP BY RoomCount
UNION
(SELECT roomcount rc,
avg(livingarea) avgArea,
count(1) c
FROM sale
WHERE url LIKE '%systemname%'
AND LivingArea IS NOT NULL
GROUP BY RoomCount))uni
GROUP BY rc) avgRoom) avgrents
JOIN rent r ON r.RoomCount = avgrents.rc) k1Rent ON k1Rent.rentid =around1k.RentId
AND base.RoomCount = k1Rent.rc
LEFT OUTER JOIN Sale k1Sale ON k1Sale.Id = around1k.SaleId
AND base.RoomCount = k1Sale.RoomCount
GROUP BY baseid) k1
left outer join SpatialAnalysis sp on sp.Id = baseid
left outer join Sale adds on adds.Id = sp.SaleId
where adds.Price < 250000
order by years, ratio

SQL Query produces duplicates with "Where IN" query

I have a large SQL statement which does a whole load of joins on my tables. I have converted some of my table relationships to many-to-many relationships so that it is more efficient. I have therefore decided to convert my SQL to do a WHERE IN statement (on location).
The following query is the one that currently returns the desired results:
ALTER PROCEDURE [dbo].[GetMemberListing]
#Locations nvarchar(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
select
Member.Id,
AspNetUsers.Salutation,
AspNetUsers.FirstName,
AspNetUsers.PhotoUrl,
AspNetUsers.LastName,
AspNetUsers.Birthday,
AspNetUsers.Gender,
Member.IDType,
Member.JoinDate,
CONCAT (AspNetUsers.FirstName, ' ', AspNetUsers.LastName) as FullName,
AspNetUsers.CountryCode,
AspNetUsers.Email,
Location.Name as LocationName,
AspNetUsers.HomePhone as HomePhone,
coalesce(Package.Name,'No Package') as PackageName,
PackageTerm = case when Package.PackageIsReoccuring = 1 then 'Recurring' when Package.PackageIsSession = 1 then 'Paid In Full' when membership.TotalPrice = 0 then 'Free' when Package.PackagePayInFull = 1 then 'Paid In Full' end,
PackageType.Name as PackageType,
MembershipId = case when membership.id IS NULL THEN '' ELSE 0 end,
coalesce(membershipstate.name, 'N/A') as MembershipState,
MembershipStartDate = case when membership.StartDate IS NULL THEN '' ELSE CONVERT(varchar(50),membership.StartDate) end,
MembershipEndDate = case when membership.EndDate IS NULL THEN '' ELSE CONVERT(varchar(50),membership.EndDate) end
from
(
select
member.id as memberid,
(
select top 1 id
from membership
where memberid = member.id
and membership.StartDate <= getdate()
order by membership.enddate desc
) as membershipid
from member
) as LatestMembership
left join membership
on latestmembership.membershipid = membership.id
join member
on latestmembership.memberid = member.id
join AspNetusers
on member.AspNetUserId = AspNetUsers.Id
join Location
on member.HomeLocationId = Location.Id
left join Package
on membership.packageid = package.Id
left join PackageType
on package.packagetypeid = packagetype.Id
left join MembershipState
on membership.membershipstateid = membershipstate.Id
Order By aspNetusers.LastName desc
END
Below is what i have tried to do; however, it is duplicating the otherwise correct results based on the number of values in the WHERE IN join.
This on member.HomeLocationId = Location.Id
becomes on member.HomeLocationId IN (SELECT Value FROM fn_Split(#Locations, ','))
As seen below:
ALTER PROCEDURE [dbo].[GetMemberListing]
#Locations nvarchar(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
select
Member.Id,
AspNetUsers.Salutation,
AspNetUsers.FirstName,
AspNetUsers.PhotoUrl,
AspNetUsers.LastName,
AspNetUsers.Birthday,
AspNetUsers.Gender,
Member.IDType,
Member.JoinDate,
CONCAT (AspNetUsers.FirstName, ' ', AspNetUsers.LastName) as FullName,
AspNetUsers.CountryCode,
AspNetUsers.Email,
Location.Name as LocationName,
AspNetUsers.HomePhone as HomePhone,
coalesce(Package.Name,'No Package') as PackageName,
PackageTerm = case when Package.PackageIsReoccuring = 1 then 'Recurring' when Package.PackageIsSession = 1 then 'Paid In Full' when membership.TotalPrice = 0 then 'Free' when Package.PackagePayInFull = 1 then 'Paid In Full' end,
PackageType.Name as PackageType,
MembershipId = case when membership.id IS NULL THEN '' ELSE 0 end,
coalesce(membershipstate.name, 'N/A') as MembershipState,
MembershipStartDate = case when membership.StartDate IS NULL THEN '' ELSE CONVERT(varchar(50),membership.StartDate) end,
MembershipEndDate = case when membership.EndDate IS NULL THEN '' ELSE CONVERT(varchar(50),membership.EndDate) end
from
(
select member.id as memberid,
(
select top 1 id
from membership
where memberid = member.id
and membership.StartDate <= getdate()
order by membership.enddate desc
) as membershipid
from member
) as LatestMembership
left join membership
on latestmembership.membershipid = membership.id
join member
on latestmembership.memberid = member.id
join AspNetusers
on member.AspNetUserId = AspNetUsers.Id
join Location
on member.HomeLocationId IN (SELECT Value FROM fn_Split(#Locations, ','))
left join Package
on membership.packageid = package.Id
left join PackageType
on package.packagetypeid = packagetype.Id
left join MembershipState
on membership.membershipstateid = membershipstate.Id
Order By aspNetusers.LastName desc
END
Change to using your split function in the where clause. Don't use that function in the join.
In addition you don't really have a valid join condition on the locations table go back to this
on member.HomeLocationId = Location.Id
And later
Where member.HomeLocationId IN (SELECT Value FROM fn_Split(#Locations, ','))

Stored Procedure Syntax with CTE

This is probably trivial but I am just learning about CTE (thanks to help here).
I have a procedure that is used to determine totals.
The first part is the totals are the sum of a position at their level an below. So I needed a way to retrieve records that (1) determined the level of the record (hierarchy) and (2) returned all records at and below. That was asked and answered here.
Now want to take the CTE table from the answer above and use it in the second part of my procedure (get the totals)
CREATE PROCEDURE [dbo].[GetProgramTotals]
#programId nvarchar(10) = null,
#owner int = null,
#totalAmount money OUT,
#usedAmount money OUT,
#remainingAmount money OUT
AS
BEGIN
WITH rCTE AS
(
SELECT
*, 0 AS Level
FROM Forecasting.dbo.Addressbook
WHERE Addressbook = #owner
UNION ALL
SELECT
t.*, r.Level + 1 AS Level
FROM Addressbook t
INNER JOIN rCTE r ON t.ParentAddressbook = r.Addressbook
)
Select #totalAmount = (Select Sum(Amount) from dbo.Budget where
(#programId IS NULL or (ProgramId = #programId)) and (#owner IS NULL or (BudgetOwner in (SELECT Addressbook from rCTE))))
Select #usedAmount = (Select Sum(SubTotal) from dbo.OrderLine where
(#programId IS NULL or (ProgramId = #programId) and (#owner IS NULL) or (Budget in (SELECT Addressbook from rCTE))))
if (#totalAmount is null)
set #totalAmount = 0
if (#usedAmount is null)
set #usedAmount = 0
Set #remainingAmount = (#totalAmount - #usedAmount)
END
The idea of this procedure is the dynamically calculate an individual (or all) programs based an a users position in a hierarchy.
So a regional managers totals would be the sum of all districts and district reps.
UPDATE: I updated this based on squillman (thank you) comment below.
Now I have a different problem. When I execute the proc - I get 'Invalid object name rCTE'.
You can't use SET in the middle of a query like that. Change it to a SELECT and it should remedy your syntax error.
CREATE PROCEDURE [dbo].[GetProgramTotals]
#programId nvarchar(10) = null,
#owner int = null,
#totalAmount money OUT,
#usedAmount money OUT,
#remainingAmount money OUT
AS
BEGIN
WITH rCTE AS(
SELECT *, 0 AS Level FROM Forecasting.dbo.Addressbook WHERE Addressbook = #owner
UNION ALL
SELECT t.*, r.Level + 1 AS Level
FROM Addressbook t
INNER JOIN rCTE r ON t.ParentAddressbook = r.Addressbook)
SELECT #totalAmount = (Select Sum(Amount) from dbo.Budget where
(#programId IS NULL or (ProgramId = #programId)) and (#owner IS NULL or (BudgetOwner in (SELECT Addressbook from rCTE))))
, #usedAmount = (Select Sum(SubTotal) from dbo.OrderLine where
(#programId IS NULL or (ProgramId = #programId) and (#owner IS NULL) or (Budget in (SELECT Addressbook from rCTE))))
if (#totalAmount is null)
set #totalAmount = 0
if (#usedAmount is null)
set #usedAmount = 0
Set #remainingAmount = (#totalAmount - #usedAmount)
END
CTE's can be a bit confusing at first, but they are really quite simple once they make sense. For me it clicked when I began thinking of them as just another temp table syntax (pro-tip: they're not in reality, just conceptually). So basically:
Create one or more "temp tables". These are your CTE expressions, and there can be more than one.
Perform a standard operation using one or more of the CTE expressions in the statement immediately following your CTE(s).
As Martin mentioned in comments below, the CTE(s) are only scoped for the next immediate statement and fall out of scope after that.
So,
;WITH cte1 AS
(
SELECT Col1 FROM Table1
),
cte2 AS
(
SELECT Col1 FROM Table2
)
SELECT Col1 FROM cte1 //In scope here
UNION
SELECT Col1 FROM cte1; //Still in scope since we're still in the first statement
SELECT Col1 FROM cte1; //Fails. cte1 is now out of scope (as is cte2)
In your case you're using the recursive CTE to form a parent/child hierarchy and then setting variables based on the results. Your CTE syntax is pretty close after the edit, you just need the comma to bring things back together into one statement.
//Variable assignment example
;WITH cte1 AS
(
SELECT Col1 FROM Table1
),
cte2 AS
(
SELECT Col1 FROM Table2
)
SELECT #var1 = (SELECT TOP 1 Col1 FROM cte1)
,#var2 = (SELECT TOP 1 Col1 FROM cte2) //You're missing the comma at the start of this line
Change Select #usedAmount=... to , #usedAmount=...

Get total number of parents

I am upgrading a legacy application and I need to find the number of parents certain rows in a table have.
I was thinking of using a declared procedure for this, but i'm having trouble figuring it out how to make it work.
Basically you have a table with id and parent
= id = parent =
= 0 = 0 =
= 1 = 0 =
= 2 = 1 =
= 3 = 1 =
= 4 = 2 =
ID is unique, and parent is variable depending on what was used to create that entry, but it will always match a row with matching ID
What i'd like to achieve is calling one procedure that returns all matching parent numbers as a simple iterable result set.
So if i were to do getAllParents(4) it should return me 2, 1, 0
My failed attempts at looping have brought me so far
CREATE PROCEDURE getNumberOfParents #start int #current int
as
begin
SELECT parent FROM test where id=#start
if(parent > 0)
begin
set #current = #current + 1;
set #current = #current + getNumberOfParents(parent,#current);
end
end
Due to restrictions I cannot use an extra table to achieve this, otherwise i'd be easy heh. i can however make temptables that can be cleaned up after the method exits.
You can do it without a while loop by the use of a recursive CTE:
DECLARE #lookupId INT = 4
;WITH ParentsCTE AS (
SELECT id, parent
FROM #mytable
WHERE id = #lookupId
UNION ALL
SELECT m.id, m.parent
FROM #mytable AS m
INNER JOIN ParentsCTE AS p ON m.id = p.parent
WHERE m.id <> m.parent
)
SELECT parent
FROM ParentsCTE
The anchor member of the above CTE:
SELECT id, parent
FROM #mytable
WHERE id = #lookupId
returns the immediate parent of the 'lookup id'.
The recursive member:
SELECT m.id, m.parent
FROM #mytable AS m
INNER JOIN ParentsCTE AS p ON m.id = p.parent
WHERE m.id <> m.parent
keeps adding parents up the hierarchy until a root node (m.id <> m.parent predicate detects this) has been reached.
SQL Fiddle Demo
Test Data
DECLARE #Table TABLE (id INT, parent INT)
INSERT INTO #Table VALUES
(0 , 0),
(1 , 0),
(2 , 1),
(3 , 1),
(4 , 2)
Query
-- Id you want all the parents for
DECLARE #ParentsFor INT = 4
;with parents as
(
select ID, parent
from #Table
where parent IS NOT NULL
union all
select p.ID, t.parent
from parents p
inner join #Table t on p.parent = t.ID
and t.ID <> t.parent
)
select Distinct
STUFF((SELECT ',' + Cast(parent AS VarChar(10))
FROM parents
WHERE ID = #ParentsFor
FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'')
FROM parents
Result
2,1,0
SQL FIDDLE
Fiddle Demo Here
try:
declare #id varchar(max)=''
declare #getid int=4
while #getid>0
begin
select #id=#id+cast(parent as varchar(10))+',' from tab_1
where id=#getid
select #getid=parent from tab_1 where id=#getid
end
select #id
Try to use while loop as presented in this example:
http://blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of-while-loop-with-continue-and-break-keywords/

selecting random records inside a UDF

I'm writing a function in sql server 2012.
I came to know that we can not use RAND() or NEWID() functions in the select statement of a function in sql server.
My function goes like this:
CREATE FUNCTION Keywordsuggester (#userid INT)
returns #suggestor_tab TABLE (
keywordid INT,
keywordname VARCHAR(max),
keywordcategory VARCHAR(max))
AS
BEGIN
DECLARE #category_table TABLE
(
category_name VARCHAR(max),
category_id INT,
rownum INT
)
DECLARE #ID INT = 1
DECLARE #COUNT INT = 0
DECLARE #I INT = 1
INSERT INTO #category_table
SELECT kc.NAME,
kc.id,
k.NAME,
d.NAME,
Row_number()
OVER(
ORDER BY d.id ASC) AS rownum
FROM dtypes d
JOIN keywords k
ON d.NAME LIKE '%' + k.NAME + '%'
JOIN keywordscategory kc
ON k.categoryid = kc.id
WHERE d.userid = #userid
SELECT #count = rownum
FROM #category_table
WHILE #count > #I
BEGIN
INSERT INTO #suggestor_tab
SELECT TOP 5 kc.id,
k.NAME,
kc.NAME
FROM kwords k
JOIN #category_table ct
ON k.categoryid = ct.category_id
JOIN kwcategory kc
ON kc.NAME = ct.category_name
WHERE ct.rownum = #I
--Here I'm inserting top 5 records for each category into the suggestor_tab,instead I have to insert random 5 records for each category(i.e.,#I)
SET #I=#I + 1
--return
END
INSERT INTO #suggestor_tab
SELECT kc.id,
k.NAME,
kc.NAME
FROM kwords k
JOIN #category_table ct
ON k.categoryid = ct.category_id
JOIN kwcategory kc
ON kc.NAME = category_name
RETURN
END
How can I get random records for each category(i.e., #I in the while loop).
I tried the query like:
SELECT TOP 5 k.NAME
FROM kwords k
JOIN #category_table ct
ON k.category_id = ct.id
JOIN kwcategory kc
ON kc.NAME = category_name
WHERE ct.rownum = #I
ORDER BY Newid()
which throws an error like:
Invalid use of a side-effecting operator 'newid' within a function.
Is there anyway to do this?
Thanks in advance.
You cannot use Non-deterministic Funcions inside UDF.
Create a View and use it in order by
create view Random
as
select newid() as New_id
Change you select something like this.
SELECT TOP 5 k.NAME
FROM KWords k
JOIN #category_table ct
ON k.category_id = ct.id
JOIN kwcategory kc
ON kc.NAME = category_name
WHERE ct.rownum = #I
ORDER BY (SELECT new_id
FROM random)

Resources