I wanted to do different comparison expression in where clause, but it keep prompt me invalid syntax. The reason i want to use this because i wanted to enforce the evaluation according to the Type. If i use ((t1.Amount <= #valueB) OR (t1.Type IN (1) AND t1.Amount > 0 AND #valueB < 0)) , it seems to be not expression i trying to impose into my query. If first evaluation success, i would not want the following to execute, however OR in sql is not short-circuit operator.
DECLARE #name AS VARCHAR(200) = 'super'
DECLARE #valueA AS INT = 1 -- Can be 1 or 2
DECLARE #valueB AS DECIMAL = 0.5
SELECT * FROM TABLE_1 t1 WITH(NOLOCK)
WHERE t1.Name = #name
AND
CASE WHEN t1.Type = 1 THEN (t1.Amount > 0 AND #valueB < 0)
ELSE (t1.Amount <= #valueB)
END
You can't use it that way.
TRY THIS
SELECT * FROM TABLE_1 t1 WITH(NOLOCK)
WHERE t1.Name = #name AND
((t1.Type = 1 AND t1.Amount > 0 AND #valueB < 0)
OR (t1.Amount <= #valueB))
If could elaborate further what you are trying to achieve , I'll be able to help.
Zohar Peled's comment rightly points out that CASE is an expression in T-SQL, it is not a flow-of-control statement.
What you are trying to do is:
IF <expression_A> = <value_A>
THEN <apply_condition_B>
ELSE <apply_condition_C>
To achieve the following in SQL, you'd need to write it out using Boolean logic using the AND and OR operators as:
(
( <expression_A> = <value_A> AND <apply_condition_B> )
OR ( <expression_A> is not <value_A> AND <apply_condition_C> )
)
The first AND that comes before <apply_condition_B> acts like the THEN keyword, while the combination of the OR and the second AND act like the ELSE keyword.
Taking your query into consideration, we get the following mapping:
<expression_A> = t1.Type
<value_A> = 1
<apply_condition_B> = (t1.Amount > 0 AND #valueB < 0)
<apply_condition_C> = (t1.Amount <= #valueB)
Putting that into query form would give us:
WHERE t1.Name = #name
AND
(
( t1.Type = 1 AND (t1.Amount > 0 AND #valueB < 0) )
OR ( t1.Type != 1 AND (t1.Amount <= #valueB) )
)
-- Note - this is not fully complete, as it assumes t1.Type is not NULL
The above is a simple rewrite of your intended logic. However, do note that SQL operates on three-valued logic which means that t1.Type can be 1, it can be a value other than 1, or it can be NULL. The above code fragment handles only two of these 3 possibilities. To correctly handle t1.Type being NULL you can use the COALESCE() function to return a specified value (zero, below) in case it is NULL:
WHERE t1.Name = #name
AND
(
( t1.Type = 1 AND (t1.Amount > 0 AND #valueB < 0) )
OR ( COALESCE(t1.Type, 0) != 1 AND (t1.Amount <= #valueB) )
)
Tip: Before using this sort of construct directly in your actual query, I'd suggest you play around with it using simpler sample data to understand how it works.
Try this
DECLARE #name AS VARCHAR(200) = 'super'
DECLARE #valueA AS INT = 1 -- Can be 1 or 2
DECLARE #valueB AS DECIMAL = 0.5
SELECT *
FROM TABLE_1 t1 WITH (NOLOCK)
WHERE t1.NAME = #name
AND (t1.Type = 1 AND (t1.Amount > 0 AND #valueB < 0)
OR t1.Type <> 1 AND (t1.Amount <= #valueB))
GO
OR Use Dynamic SQL if you feel like it
DECLARE #name AS VARCHAR(200) = 'super'
DECLARE #valueA AS INT = 1 -- Can be 1 or 2
DECLARE #valueB AS DECIMAL = 0.5
DECLARE #SQL VARCHAR(MAX)
DECLARE #Type INT
SELECT TOP 1 #Type = t1.Type
FROM TABLE_1 t1 WITH (NOLOCK)
WHERE t1.NAME = #name
SET #SQL = 'SELECT *
FROM TABLE_1 t1 WITH (NOLOCK)
WHERE t1.NAME = #name'
SET #SQL = CASE
WHEN #Type = 1
THEN #SQL + CHAR(13)+CHAR(10) + ' AND (t1.Amount > 0 AND #valueB < 0)'
ELSE #SQL + CHAR(13)+CHAR(10) + ' AND (t1.Amount <= #valueB)'
END
--PRINT #SQL
EXEC (#SQL)
GO
Related
I am getting the error in the below sql queries. For osdsId variable, I will get values as a list from the UI. That's why I hardcoded the value for testing. But it is displaying error as 'Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.' However, it works if I just assign just one value. Thank you.
declare #osdsId VARCHAR(max) = '4292, 4293',
#pqrId VARCHAR(max) = NULL,
#queryOrderBy VARCHAR(max) = 'DATE_INSERTED ASC',
#rowLimit INT = 0,
#startRow INT = 0,
#endRow INT = 0
SELECT * FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY #queryOrderBy ) AS ROWNUM,
S.OSDS_ID,
S.PQR_ID,
S.DATE_INSERTED,
S.BUY_CURRENCY,
S.SELL_CURRENCY,
S.BUY_EXCHANGE_RATE,
S.SELL_EXCHANGE_RATE,
S.BUY_PERCENT,
S.SELL_PERCENT
FROM
table1 S
WHERE
1=1
AND S.OSDS_ID IN (COALESCE((SELECT TXT_VALUE FROM
DBO.FN_PARSETEXT2TABLE_TEXTONLY(#osdsId, ',') ), S.OSDS_ID))
AND S.PQR_ID IN (COALESCE((SELECT TXT_VALUE FROM
DBO.FN_PARSETEXT2TABLE_TEXTONLY(#pqrId, ',') ), S.PQR_ID))
)x
WHERE ROWNUM BETWEEN
CASE WHEN (#rowLimit > 0) THEN #startRow ELSE ROWNUM END
AND CASE WHEN (#rowLimit > 0) THEN #endRow ELSE ROWNUM END
I believe it's because your FN_PARSETEXT2TABLE_TEXTONLY is returning a table, but COALESCE expects its arguments to be a single value. So, when two values are returned from the table, that's where the error comes from. You could add a TOP 1, but that would defeat the purpose.
What I would do: declare a table variable and run the UDF on it outside of your query. It's inefficient to run that within a sub-query anyway since it's consistent throughout execution.
I'm not clear on why you are using the COALESCE though. Is that for if the parsing function fails and returns a NULL, you still want it to return something? Because it will return everything in that case.
So, assuming that your FN_PARSETEXT2TABLE_TEXTONLY returns a table with a single integer column:
declare #osdsId VARCHAR(max) = '4292, 4293',
#pqrId VARCHAR(max) = NULL,
#queryOrderBy VARCHAR(max) = 'DATE_INSERTED ASC',
#rowLimit INT = 0,
#startRow INT = 0,
#endRow INT = 0,
#osdsTbl TABLE (oid INT),
#pqrTbl TABLE (pid INT);
SET #osdsTbl = DBO.FN_PARSETEXT2TABLE_TEXTONLY(#osdsId, ',');
SET #pqrTbl = DBO.FN_PARSETEXT2TABLE_TEXTONLY(#pqrId, ',');
SELECT * FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY #queryOrderBy ) AS ROWNUM,
S.OSDS_ID,
S.PQR_ID,
S.DATE_INSERTED,
S.BUY_CURRENCY,
S.SELL_CURRENCY,
S.BUY_EXCHANGE_RATE,
S.SELL_EXCHANGE_RATE,
S.BUY_PERCENT,
S.SELL_PERCENT
FROM
table1 S
WHERE
1=1
AND (#osdsId IS NULL OR (#osdsId IS NOT NULL AND S.OSDS_ID IN (SELECT * FROM #osdsTbl))
AND (#pqrId IS NULL OR (#pqrId IS NOT NULL AND S.PQR_ID IN (SELECT * FROM #pqrTbl))
)x
WHERE ROWNUM BETWEEN
CASE WHEN (#rowLimit > 0) THEN #startRow ELSE ROWNUM END
AND CASE WHEN (#rowLimit > 0) THEN #endRow ELSE ROWNUM END
Getting error:
Msg 512, Level 16, State 1, Line 48
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Msg 512, Level 16, State 1, Line 87
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Need to check each record in the table and update a table if there is no records = to 0,00. Then update an existing table with current values. I want to be able to track current data and compare with old data.
DECLARE #LocTime DATETIME;
DECLARE #MinDateTime DATETIME;
DECLARE #SystemDateTime DATETIME;
DECLARE #LIR MONEY;
DECLARE #LOAR MONEY;
SELECT #SystemDateTime = SYSDATETIME(); --= '2016-12-07 23:30:00'
SELECT #MinDateTime = DATEADD(mi,-30,#SystemDateTime) --go back half hour of reads, job is running every 10 minutes for overlap
--select #MinDateTime, #SystemDateTime
IF OBJECT_ID(N'tempdb..##LastOver2') IS NOT NULL
BEGIN
DROP TABLE ##LastOver2
END
--make temp table to hold found data
CREATE TABLE ##LastOver2 (ReadDate DATETIME
, FacilityName NVARCHAR(100)
, FacilityID UNIQUEIDENTIFIER
, LastInstantRead MONEY
, LastOverAllRead MONEY
, FacilityTimeZone INT
, FacilityTime DATETIME)
INSERT INTO ##LastOver2 (ReadDate, FacilityName
, FacilityID, LastInstantRead
, LastOverAllRead
, FacilityTimeZone, FacilityTime)
SELECT DISTINCT --why distinct?
fmr.ReadDate, f.Name
, f.FacilityID, fm.LastInstantRead
, fm.LastOverAllRead
, f.Timezone
, #LocTime
FROM [dbo].[Facilities] f WITH (NOLOCK)
JOIN [dbo].[FacilityMeters] fm WITH (NOLOCK)
ON F.FacilityID = FM.FacilityID
JOIN FacilityMeterReadings fmr WITH (NOLOCK)
ON FM.FacilityMeterID = FMR.FacilityMeterID
WHERE --fm.FacilityMeterID = '9268d1af-cc29-432c-9cdb-06c158180d2f'
(fmr.ReadDate >= #MinDateTime and ReadDate <= #SystemDateTime) --including on both side to continue with overlap
and (fm.IsVirtual = 0 and fm.ParentMeterID is NULL)
--and (fm.LastInstantRead = 0.00 and fm.LastOverAllRead = 0.00)
AND f.SuppressMonitoring = 0
select * from ##LastOver2
IF (select LastInstantRead from ##LastOver2) = 0.00 OR (SELECT LastOverAllRead FROM ##LastOver2) = 0.00
BEGIN
--UPDATE dbo.Facilities
--SET SuppressMonitoring = 1
-- FROM dbo.Facilities F
-- JOIN ##LastOver L
-- ON F.FacilityID = l.FacilityID
-- WHERE F.FacilityID = l.FacilityID
DECLARE #body_content NVARCHAR(150);
DECLARE #StartHour NVARCHAR(8) = '08:30:00' ;
DECLARE #StopHour NVARCHAR(8) = '16:00:00';
--why distinct, is it already distinct. Is is supposed to distinct the facility or meter?
DECLARE #SQLScript NVARCHAR(200) = 'SELECT distinct * FROM ##LastOver2 WHERE CONVERT(TIME, FacilityTime) BETWEEN '
+ CHAR(39) + #StartHour + CHAR(39) +' AND ' + CHAR(39) + #StopHour + CHAR(39);
--only looking for reads during day hours? shouldn't use between.
DECLARE #copyRecipients NVARCHAR(100)
SET #body_content = 'Please check the attached file. This was from server: ' + ##SERVERNAME
DECLARE #fileName nvarchar(255);
select #fileName = 'BadReading_' + replace(replace(convert(nvarchar(19),getdate(), 126),':',''),'-','') + '.txt';
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'SQLSupport'
,#recipients = 'Btest#test.com'
--, #recipients = 'jira#cleanenergycollective.atlassian.net'
--, #copy_recipients= #copyRecipients
--, #copy_recipients= 'Bill.Lugaila#easycleanenergy.com;yvonne.lewis#easycleanenergy.com;don.munroe#easycleanenergy.com;Justin.Reed#easycleanenergy.com'
, #query = #SQLScript
, #subject = 'Facility Meter Check and Updating table' --change so easier to see in emails
, #body= #body_content
, #importance= 'High'
, #attach_query_result_as_file = 1
, #query_attachment_filename = #fileName ;
--select #SQLScript
END
ELSE IF (select LastInstantRead from ##LastOver2) != 0.00 OR (SELECT LastOverAllRead FROM ##LastOver2) != 0.00
BEGIN
UPDATE [dbo].[_LastInstant_OverAll_Read]
SET [FacilityName] = lo.FacilityName,
[LastInstantRead] = lo.LastInstantRead,
[LastOverAllRead]= lo.LastOverAllRead,
[Time_Date] = (SELECT CONVERT(DateTime, SysDateTime()))
FROM ##LastOver2 lo
WHERE lo.FacilityName = [dbo].[_LastInstant_OverAll_Read].FacilityName
AND lo.LastInstantRead != [dbo].[_LastInstant_OverAll_Read].LastInstantRead
AND lo.LastOverAllRead != [dbo].[_LastInstant_OverAll_Read].LastOverAllRead
END
the following could be returning multiple rows:
.
.
.
IF
(
SELECT LastInstantRead
FROM ##LastOver2
) = 0.00
OR
(
SELECT LastOverAllRead
FROM ##LastOver2
) = 0.00
.
.
.
IF
(
SELECT LastInstantRead
FROM ##LastOver2
) != 0.00
OR
(
SELECT LastOverAllRead
FROM ##LastOver2
) != 0.00
if you are expecting them to return only 1 row then you will need to fix the issue with the following query:
SELECT DISTINCT --why distinct?
fmr.ReadDate,
f.Name,
f.FacilityID,
fm.LastInstantRead,
fm.LastOverAllRead,
f.Timezone,
#LocTime
FROM [dbo].[Facilities] f WITH (NOLOCK)
JOIN [dbo].[FacilityMeters] fm WITH (NOLOCK) ON F.FacilityID = FM.FacilityID
JOIN FacilityMeterReadings fmr WITH (NOLOCK) ON FM.FacilityMeterID = FMR.FacilityMeterID
WHERE --fm.FacilityMeterID = '9268d1af-cc29-432c-9cdb-06c158180d2f'
(fmr.ReadDate >= #MinDateTime
AND ReadDate <= #SystemDateTime) --including on both side to continue with overlap
AND (fm.IsVirtual = 0
AND fm.ParentMeterID IS NULL)
--and (fm.LastInstantRead = 0.00 and fm.LastOverAllRead = 0.00)
AND f.SuppressMonitoring = 0;
Let's say I have a set of 2 words:
Alexander and Alecsander OR Alexander and Alegzander
Alexander and Aleaxnder, or any other combination. In general we are talking about human error in typing of a word or a set of words.
What I want to achieve is to get the percentage of matching of the characters of the 2 strings.
Here is what I have so far:
DECLARE #table1 TABLE
(
nr INT
, ch CHAR
)
DECLARE #table2 TABLE
(
nr INT
, ch CHAR
)
INSERT INTO #table1
SELECT nr,ch FROM [dbo].[SplitStringIntoCharacters] ('WORD w') --> return a table of characters(spaces included)
INSERT INTO #table2
SELECT nr,ch FROM [dbo].[SplitStringIntoCharacters] ('WORD 5')
DECLARE #resultsTable TABLE
(
ch1 CHAR
, ch2 CHAR
)
INSERT INTO #resultsTable
SELECT DISTINCt t1.ch ch1, t2.ch ch2 FROM #table1 t1
FULL JOIN #table2 t2 ON t1.ch = t2.ch --> returns both matches and missmatches
SELECT * FROM #resultsTable
DECLARE #nrOfMathches INT, #nrOfMismatches INT, #nrOfRowsInResultsTable INT
SELECT #nrOfMathches = COUNT(1) FROM #resultsTable WHERE ch1 IS NOT NULL AND ch2 IS NOT NULL
SELECT #nrOfMismatches = COUNT(1) FROM #resultsTable WHERE ch1 IS NULL OR ch2 IS NULL
SELECT #nrOfRowsInResultsTable = COUNT(1) FROM #resultsTable
SELECT #nrOfMathches * 100 / #nrOfRowsInResultsTable
The SELECT * FROM #resultsTable will return the following:
ch1 ch2
NULL 5
[blank] [blank]
D D
O O
R R
W W
Ok, here is my solution so far:
SELECT [dbo].[GetPercentageOfTwoStringMatching]('valentin123456' ,'valnetin123456')
returns 86%
CREATE FUNCTION [dbo].[GetPercentageOfTwoStringMatching]
(
#string1 NVARCHAR(100)
,#string2 NVARCHAR(100)
)
RETURNS INT
AS
BEGIN
DECLARE #levenShteinNumber INT
DECLARE #string1Length INT = LEN(#string1)
, #string2Length INT = LEN(#string2)
DECLARE #maxLengthNumber INT = CASE WHEN #string1Length > #string2Length THEN #string1Length ELSE #string2Length END
SELECT #levenShteinNumber = [dbo].[LEVENSHTEIN] ( #string1 ,#string2)
DECLARE #percentageOfBadCharacters INT = #levenShteinNumber * 100 / #maxLengthNumber
DECLARE #percentageOfGoodCharacters INT = 100 - #percentageOfBadCharacters
-- Return the result of the function
RETURN #percentageOfGoodCharacters
END
-- =============================================
-- Create date: 2011.12.14
-- Description: http://blog.sendreallybigfiles.com/2009/06/improved-t-sql-levenshtein-distance.html
-- =============================================
CREATE FUNCTION [dbo].[LEVENSHTEIN](#left VARCHAR(100),
#right VARCHAR(100))
returns INT
AS
BEGIN
DECLARE #difference INT,
#lenRight INT,
#lenLeft INT,
#leftIndex INT,
#rightIndex INT,
#left_char CHAR(1),
#right_char CHAR(1),
#compareLength INT
SET #lenLeft = LEN(#left)
SET #lenRight = LEN(#right)
SET #difference = 0
IF #lenLeft = 0
BEGIN
SET #difference = #lenRight
GOTO done
END
IF #lenRight = 0
BEGIN
SET #difference = #lenLeft
GOTO done
END
GOTO comparison
COMPARISON:
IF ( #lenLeft >= #lenRight )
SET #compareLength = #lenLeft
ELSE
SET #compareLength = #lenRight
SET #rightIndex = 1
SET #leftIndex = 1
WHILE #leftIndex <= #compareLength
BEGIN
SET #left_char = substring(#left, #leftIndex, 1)
SET #right_char = substring(#right, #rightIndex, 1)
IF #left_char <> #right_char
BEGIN -- Would an insertion make them re-align?
IF( #left_char = substring(#right, #rightIndex + 1, 1) )
SET #rightIndex = #rightIndex + 1
-- Would an deletion make them re-align?
ELSE IF( substring(#left, #leftIndex + 1, 1) = #right_char )
SET #leftIndex = #leftIndex + 1
SET #difference = #difference + 1
END
SET #leftIndex = #leftIndex + 1
SET #rightIndex = #rightIndex + 1
END
GOTO done
DONE:
RETURN #difference
END
Ultimately, you appear to be looking to solve for the likelihood that two strings are a "fuzzy" match to one another.
SQL provides efficient, optimized built-in functions that will do that for you, and likely with better performance than what you have written. The two functions you are looking for are SOUNDEX and DIFFERENCE.
While neither of them solves exactly what you asked for - i.e. they do not return a percentage match - I believe they solve what you are ultimately trying to achieve.
SOUNDEX returns a 4-character code which is the first letter of the word plus a 3-number code that represents the sound pattern of the word. Consider the following:
SELECT SOUNDEX('Alexander')
SELECT SOUNDEX('Alegzander')
SELECT SOUNDEX('Owleksanndurr')
SELECT SOUNDEX('Ulikkksonnnderrr')
SELECT SOUNDEX('Jones')
/* Results:
A425
A425
O425
U425
J520
*/
What you will notice is that the three-digit number 425 is the same for all of the ones that roughly sound alike. So you could easily match them up and say "You typed 'Owleksanndurr', did you perhaps mean 'Alexander'?"
In addition, there's the DIFFERENCE function, which compares the SOUNDEX discrepancy between two strings and gives it a score.
SELECT DIFFERENCE( 'Alexander','Alexsander')
SELECT DIFFERENCE( 'Alexander','Owleksanndurr')
SELECT DIFFERENCE( 'Alexander', 'Jones')
SELECT DIFFERENCE( 'Alexander','ekdfgaskfalsdfkljasdfl;jl;asdj;a')
/* Results:
4
3
1
1
*/
As you can see, the lower the score (between 0 and 4), the more likely the strings are a match.
The advantage of SOUNDEX over DIFFERENCE is that if you really need to do frequent fuzzy matching, you can store and index the SOUNDEX data in a separate (indexable) column, whereas DIFFERENCE can only calculate the SOUNDEX at the time of comparison.
I am trying to establish upper / lower bound in my stored procedure
below and am having some problems at the end (I am getting no results
where, without the temp table inner join i get the expected results).
I need some help where I am trying to join the columns in my temp table #PageIndexForUsers
to the rest of my join statement and I am mucking something up with
this statement:
INNER JOIN
#PageIndexForUsers ON ( dbo.aspnet_Users.UserId =
#PageIndexForUsers.UserId AND #PageIndexForUsers.IndexId >= #PageLowerBound AND
#PageIndexForUsers.IndexId <= #PageUpperBound )
I could use feedback at this point - and, any advice on how to improve
my procedure's logic (if you see anything else that needs improvement) is also appreciated.
Thanks in advance...
ALTER PROCEDURE dbo.wb_Membership_GetAllUsers
#ApplicationName nvarchar(256),
#sortOrderId smallint = 0,
#PageIndex int,
#PageSize int
AS
BEGIN
DECLARE #ApplicationId uniqueidentifier
SELECT #ApplicationId = NULL
SELECT #ApplicationId = ApplicationId FROM dbo.aspnet_Applications WHERE LOWER(#ApplicationName) = LoweredApplicationName
IF (#ApplicationId IS NULL)
RETURN 0
-- Set the page bounds
DECLARE #PageLowerBound int
DECLARE #PageUpperBound int
DECLARE #TotalRecords int
SET #PageLowerBound = #PageSize * #PageIndex
SET #PageUpperBound = #PageSize - 1 + #PageLowerBound
BEGIN TRY
-- Create a temp table TO store the select results
CREATE TABLE #PageIndexForUsers
(
IndexId int IDENTITY (0, 1) NOT NULL,
UserId uniqueidentifier
)
-- Insert into our temp table
INSERT INTO #PageIndexForUsers (UserId)
SELECT u.UserId
FROM dbo.aspnet_Membership m, dbo.aspnet_Users u
WHERE u.ApplicationId = #ApplicationId AND u.UserId = m.UserId
ORDER BY u.UserName
SELECT #TotalRecords = ##ROWCOUNT
SELECT dbo.wb_Profiles.profileid, dbo.wb_ProfileData.firstname, dbo.wb_ProfileData.lastname, dbo.wb_Email.emailaddress, dbo.wb_Email.isconfirmed, dbo.wb_Email.emaildomain, dbo.wb_Address.streetname, dbo.wb_Address.cityorprovince, dbo.wb_Address.state, dbo.wb_Address.postalorzip, dbo.wb_Address.country, dbo.wb_ProfileAddress.addresstype,dbo.wb_ProfileData.birthday, dbo.wb_ProfileData.gender, dbo.wb_Session.sessionid, dbo.wb_Session.lastactivitydate, dbo.aspnet_Membership.userid, dbo.aspnet_Membership.password, dbo.aspnet_Membership.passwordquestion, dbo.aspnet_Membership.passwordanswer, dbo.aspnet_Membership.createdate
FROM dbo.wb_Profiles
INNER JOIN dbo.wb_ProfileAddress
ON
(
dbo.wb_Profiles.profileid = dbo.wb_ProfileAddress.profileid
AND dbo.wb_ProfileAddress.addresstype = 'home'
)
INNER JOIN dbo.wb_Address
ON dbo.wb_ProfileAddress.addressid = dbo.wb_Address.addressid
INNER JOIN dbo.wb_ProfileData
ON dbo.wb_Profiles.profileid = dbo.wb_ProfileData.profileid
INNER JOIN dbo.wb_Email
ON
(
dbo.wb_Profiles.profileid = dbo.wb_Email.profileid
AND dbo.wb_Email.isprimary = 1
)
INNER JOIN dbo.wb_Session
ON dbo.wb_Profiles.profileid = dbo.wb_Session.profileid
INNER JOIN
dbo.aspnet_Membership
ON dbo.wb_Profiles.userid = dbo.aspnet_Membership.userid
INNER JOIN
dbo.aspnet_Users
ON dbo.aspnet_Membership.UserId = dbo.aspnet_Users.UserId
INNER JOIN
dbo.aspnet_Applications
ON dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
INNER JOIN
#PageIndexForUsers ON ( dbo.aspnet_Users.UserId =
#PageIndexForUsers.UserId AND #PageIndexForUsers.IndexId >= #PageLowerBound AND
#PageIndexForUsers.IndexId <= #PageUpperBound )
ORDER BY CASE #sortOrderId
WHEN 1 THEN dbo.wb_ProfileData.lastname
WHEN 2 THEN dbo.wb_Profiles.username
WHEN 3 THEN dbo.wb_Address.postalorzip
WHEN 4 THEN dbo.wb_Address.state
END
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0 ROLLBACK TRAN
EXEC wb_ErrorHandler
RETURN 55555
END CATCH
RETURN #TotalRecords
END
GO
You don't have enough rows in #PageIndexForUsers, no?
If #PageSize = 50 and you want #PageIndex 2, then you are looking for rows 100 to 149 from #PageIndexForUsers. Do you have this many rows?
The row filter should be applied over the larger dataset that starts FROM dbo.wb_Profiles
I have this statement in T-SQL.
SELECT Bay From TABLE where uid in (
select B_Numbers from Info_Step WHERE uid = 'number'
)
I am selecting "multiple" BAYs from TABLE where their uid is equal to a string of numbers like this:
B_Numbers = 1:45:34:98
Therefore, I should be selecting 4 different BAYs from TABLE. I basically need to split the string 1:45:34:98 up into 4 different numbers.
I'm thinking that Split() would work, but it doesn't and I get a syntax error.
Any thoughts from the T-SQL gods would be awesome!
Here is an implementation of a split function that returns the list of numbers as a table:
http://rbgupta.blogspot.com/2007/03/split-function-tsql.html
Looks like this would set you on your way...
Here is a method that uses an auxiliary numbers table to parse the input string. The logic can easily be added to a function that returns a table. That table can then be joined to lookup the correct rows.
Step 1: Create the Numbers table
SET NOCOUNT ON
GO
IF EXISTS
(
SELECT 1
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Numbers'
AND TABLE_SCHEMA = 'dbo'
AND TABLE_TYPE = 'BASE TABLE'
)
BEGIN
DROP TABLE dbo.Numbers
END
GO
CREATE TABLE dbo.Numbers
(
Number smallint IDENTITY(1, 1) PRIMARY KEY
)
GO
WHILE 1 = 1
BEGIN
INSERT INTO dbo.Numbers DEFAULT VALUES
IF SCOPE_IDENTITY() = 32767
BEGIN
BREAK
END
END
GO
Step 2: Parse the Input String
CREATE FUNCTION dbo.ParseString(#input_string varchar(8000), #delim varchar(8000) = " ")
RETURNS TABLE
AS RETURN
(
SELECT Number
FROM dbo.Numbers
WHERE CHARINDEX
(
#delim + CONVERT(VARCHAR(12),Number) + #delim,
#delim + #input_string + #delim
) > 0
)
GO
**EXAMPLE**
SELECT * FROM dbo.ParseString('1:45:34:98',':')
Step 3: Use the results however you want/need
Number
------
1
34
45
98
End-To-End Example
Create function that returns the appropriate BNumber (of course change it to use the commented out SQL)
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION dbo.GetBNumber (#uid int)
RETURNS VARCHAR(8000)
AS
BEGIN
RETURN '1:45:34:98'
--select B_Numbers from Info_Step WHERE uid = #uid
END
GO
Use the use functions to return the desired results
-- Using Test Data
SELECT N.Number FROM Numbers N
JOIN dbo.ParseString(dbo.GetBNumber(12345),':') Q ON Q.Number = N.Number
-- Using Your Data (Untested but should work.)
SELECT N.Bay
FROM TABLE N
JOIN dbo.ParseString(dbo.GetBNumber(ENTER YOU NUMBER HERE),':') Q ON Q.Number = N.uid
Results
Number
------
1
34
45
98
You should keep your arrays as rows but if I understand your question I think this will work.
SELECT
Bay
From
TABLE
join Info_Step
on B_Numbers like '%'+ uid +'%'
where
Info_Step.uid = 'number'
This query will do a full table scan because of the like operator.
What you can do is loop through the B_Numbers entries and do your own split on : Insert those entries into a temp table and then perform your query.
DECLARE #i int
DECLARE #start int
DECLARE #B_Numbers nvarchar(20)
DECLARE #temp table (
number nvarchar(10)
)
-- SELECT B_Numbers FROM Info_Step WHERE uid = 'number'
SELECT #B_Numbers = '1:45:34:98'
SET #i = 0
SET #start = 0
-- Parse out characters delimited by ":";
-- Would make a nice user defined function.
WHILE #i < len(#B_Numbers)
BEGIN
IF substring(#B_Numbers, #i, 1) = ':'
BEGIN
INSERT INTO #temp
VALUES (substring(#B_Numbers, #start, #i - #start))
SET #start = #i + 1
END
SET #i = #i + 1
END
-- Insert last item
INSERT INTO #temp
VALUES (substring(#B_Numbers, #start, #i - #start + 1))
-- Do query with parsed values
SELECT Bay FROM TABLE WHERE uid in (SELECT * FROM #temp)
You can even try this
declare #str varchar(50)
set #str = '1:45:34:98'
;with numcte as(
select 1 as rn union all select rn+1 from numcte where rn<LEN(#str)),
getchars as(select
ROW_NUMBER() over(order by rn) slno,
rn,chars from numcte
cross apply(select SUBSTRING(#str,rn,1) chars)X where chars = ':')
select top 1
Bay1 = SUBSTRING(#str,0,(select rn from getchars where slno = 1))
,Bay2 = SUBSTRING(#str,
(select rn from getchars where slno = 1) + 1,
(((select rn from getchars where slno = 2)-
(select rn from getchars where slno = 1)
)-1))
,Bay3 = SUBSTRING(#str,
(select rn from getchars where slno = 2) + 1,
(((select rn from getchars where slno = 3)-
(select rn from getchars where slno = 2)
)-1))
,Bay4 = SUBSTRING(#str,
(select rn from getchars where slno = 3)+1,
LEN(#str))
from getchars
Output:
Bay1 Bay2 Bay3 Bay4
1 45 34 98