I have an instance where sometimes we aren't sure to filter by the name text or the name id. I've solved this with a case statement and isnumeric. For example, we have both the id and name values but we're not sure which column is being asked to filter. rtresource.id is numeric, and in this case we have the value '183' to work with. If rtresource.rname (varchar) is trying to filter, then we have the rname for that id 'Jane Thompson'.
So the filter is either
rtresource.id=183
Or
rtresource.rname='Jane Thompson'
Instead becomes
rtresource.rname in (CASE IsNumeric(rtresource.rname) WHEN 1 then '183' else 'Jane Thompson' End)
This works awesome. The issue is having more than one set of id/rname being passed. Typically, we would ask either rtresource.id in (183, 23) or rtresource.rname in ('Jane Thompson','John Doe'). How can I solve this with a case statement?
rtresource.rname in (CASE IsNumeric(rtresource.rname) WHEN 1 then ('183','23') else ('Jane Thompson','John Doe') End)
Above complains over the commas between values. I've also tried:
rtresource.rname in (CASE IsNumeric(rtresource.rname) WHEN 1 then ('183'+','+'23') else ('Jane Thompson'+','+'John Doe') End)
Which doesn't work either. Ideas? Thanks for any help in advance.
You have to repeat the case for every value in the list:
where rtresource.rname in (
CASE IsNumeric(rtresource.rname) WHEN 1 then '183' else 'Jane Thompson' End,
CASE IsNumeric(rtresource.rname) WHEN 1 then '23' else 'John Doe' End
)
or since the values don't intersect, just:
where rtresource.rname in (183, 23, 'Jane Thompson', 'John Doe')
which would perform much better as it will use an index (if any) of the column, and is easier to code, understand and scale.
Figured it out. Skip the case and instead:
(IsNumeric(rtresource.rname) = 1 and rtresource.rname in ('183','23'))
or
(IsNumeric(rtresource.rname) != 1 and rtresource.rname in ('Jane Thompson','John Doe'))
Related
I have a problem which I think relates to having a multiple value parameter.
In my TblActivity there are two fields TblActivity.ActivityServActId and TblActivity.ActivityContractId which I want to include in my WHERE statement.
Filtering by these is optional. If the user selects 'Yes' for the parameter #YESNOActivity, then I want to filter the query looking for rows where TblActivity.ActivityServActId matches one of the options in the parameter #ServiceActivity.
The same goes for the #YESNOContract, TblActivity.ActivityContractId and #Contract respectively
I managed to get to this:
WHERE
(CASE WHEN #YESNOActivity = 'Yes' THEN TblActivity.ActivityServActId ELSE 0 END)
IN (CASE WHEN #YESNOActivity = 'Yes' THEN #ServiceActivity ELSE 0 END)
AND (CASE WHEN #YESNOContract = 'Yes' THEN TblActivity.ActivityContractId ELSE 0 END)
IN (CASE WHEN #YESNOContract = 'Yes' THEN #Contract ELSE 0 END)
However, although this code works fine if there is only one value selected in the parameter #ServiceActivity or #Contract, as soon as I have more than one value in these parameters, I get the error:
Incorrect syntax near ','.
Query execution failed for dataset 'Activity'. (rsErrorExecutingCommand)
An error has occurred during report processing. (rsProcessingAborted)
Can anyone see what I'm doing wrong? I could understand it if I had an = instead of IN in the WHERE statement but can't figure this one out.
Using SQL Server 2008 and SSRS 2008-r2
If your #ServiceActivity is something like 1,2,3
You can do something like this
WHERE `,1,2,3,` LIKE `%,1,%`
So you format your variables
WHERE ',' + #ServiceActivity + ',' LIKE '%,' + ID + ',%'
SQL FIDDLE DEMO
SELECT *
FROM
(SELECT '1,2,3,4' as X UNION ALL
SELECT '2,3,4,5' as X UNION ALL
SELECT '3,4,5,6' as X UNION ALL
SELECT '1,3,4,5' as X
) as T
WHERE ',' + X + ',' LIKE '%,1,%'
For Your Case
(CASE WHEN #YESNOActivity = 'Yes'
THEN ',' + #ServiceActivity + ','
ELSE NULL
END)
LIKE
(CASE WHEN #YESNOActivity = 'Yes'
THEN '%,' + TblActivity.ActivityServActId + ',%'
ELSE 0
END)
In SQL, the IN clause does not support parameters the way you are using them. The general syntax is
IN (1, 2, 3, 4)
you have
IN (#Param)
where something like
#Param = '1, 2, 3, 4'
Internally, SQL will turn this into
IN ('1, 2, 3, 4')
Note the quotes... you are now matching against a string!
There are a number of ways to address this. Search SO for "sql in clause parameter", pick one that works for you, and upvote it.
(Added)
Parameterize an SQL IN clause seems pretty definitive on the subject. While long ago I upvoted the third reply (the one with table-value parameters), any of the high-vote answers could do the trick. The ideal answer depends on the overall problem you are working with. (I am not familiar with SSRS, and can't give more specific advice.)
So after a lot of messing around I put together a simple workaround for this by dropping my use of CASE altogether - but I have a suspicion that this is not a terribly efficient way of doing things.
WHERE
(#YESNOActivity = 'No' OR (#YESNOActivity = 'Yes' AND
TblActivity.ActivityServActId IN (#ServiceActivity)))
AND
(#YESNOContract = 'No' OR (#YESNOContract = 'Yes' AND
TblActivity.ActivityContractId IN (#Contract)))
How we select record in given mysql query :
kindly help me to select query with case when var1 like value1 or var2 like value2 then 'valid' else 'invalid' from xx as s
select
case
when SUBSTRING(Trim(Pan_No), 4, 1) ='C'
and (z.tds_Vendor_Type_Lookup_Code not like '%COMP%' or Vendor_Name not like '%Pvt%' or Vendor_Name not like '%Ldt%' or Vendor_Name not like '%Limited%' or Vendor_Name not like '%Private%' )
then 'InValid Pan 4th Character for a Company' end as code
from xyz as a
in this query always run else condition please guide me a valid way.
You are missing the end statement for the case, in addition you can also add else something as
select
case
when SUBSTRING(Trim(Pan_No), 4, 1) ='C'
and (
z.tds_Vendor_Type_Lookup_Code not like '%COMP%'
or Vendor_Name not like '%Pvt%'
or Vendor_Name not like '%Ldt%'
or Vendor_Name not like '%Limited%'
or Vendor_Name not like '%Private%'
)
then 'InValid Pan 4th Character for a Company'
else 'Valid' end as validity
from xyz
I have an auto-increment transactionID type=MEDIUMINT(9) in my table. I want to also display a unique 4-character (which can grow over time, but 4 for now) alphabetical Redemption Code to my users. What is the best way to derive this alphabetical code from my transactionID, preferably straight from the SELECT statement?
That mostly depends on what alphabet you want to use.
You may use TO_BASE64 to convert it it to base64 encoded string or simply do something like:
select REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(your_number, '0', 'A')
, '1', 'B')
, '2', 'C')
, '3', 'D')
, '4', 'E')
, '5', 'F')
, '6', 'G')
, '7', 'H')
, '8', 'I')
, '9', 'J')
if you want custom alphabet.
In case you want something shorter, you can go a slightly harder way:
You use 9-digit decimal (maximum 999999999), which translates to 8 hex digits (0x3B9AC9FF), i.e. 4 bytes. What you can do is divide your number in 4 binary octets, convert them to chars, construct new string and feed it to TO_BASE64():
select TO_BASE64(CONCAT(CHAR(FLOOR(your_number/(256*256*256))%256),CHAR(FLOOR(your_number/(256*256))%256),CHAR(FLOOR(your_number/256)%256),CHAR(your_number%256)))
Note, that TO_BASE64() function is available only in MySQL 5.6 on-wards.
Now, for those on older versions - we don't want to implement base64 encoding with our bare hands, don't we? So, lets go the easier way: we have 30 bits in those 9 decimal digits, which would be 30/6=5 characters, if we use 64 continuous character alphabet after CHAR(32), which is space, which we don't want to use:
SELECT CONCAT(`enter code here`CHAR(FLOOR(your_number/(64*64*64*64))%64+33),CHAR(FLOOR(your_number/(64*64*64))%64+33),CHAR(FLOOR(your_number/(64*64))%64+33),CHAR(FLOOR(your_number/64)%64+64),CHAR(your_number%64+33))
I was just looking for something like this and I found a way to do it with the CONV function.
CONV(9+your_number, 10, 36)
This converts 1 to A, 2 to B etc.
The way it works is by adding 9 and then converting to base 36, in which 10 is A, 11 is B etc.
You can generate a hash with the value of transaction id.
Like:
SELECT MD5(transactionID) FROM `yourtable`;
There are several other types of similar functions you can use.
Maybe can use CASE WHEN() END; and stored procedure
For example:
CREATE DEFINER = 'USERNAME'#'HOST' STORED PROCEDURE `ConvertNumberToAlphabetic`
BEGIN
SELECT
(CASE
WHEN (your_number = '1') THEN 'A'
WHEN (your_number = '2') THEN 'B'
WHEN (your_number = '3') THEN 'C'
WHEN (your_number = '4') THEN 'D'
WHEN (your_number = '5') THEN 'E'
WHEN (your_number = '6') THEN 'F'
WHEN (your_number = '7') THEN 'G'
WHEN (your_number = '8') THEN 'H'
WHEN (your_number = '9') THEN 'J'
WHEN (your_number = '10') THEN 'K'
END) RedeemCode
FROM tblTransaction;
END
SELECT SUBSTRING(MD5(transactionId) FROM 1 FOR 4) AS RedemptionCode
This creates a 4 character (easy to change, as you can see) string where the characters are from the MD5 command (and therefore in the range a-z and 0-9).
Reorder rows
A row in my database it in a random order with the following characters
HFMNLBX#&I
It was input weirdly and the rows are like HF and FH, which are both equivalent to the system. Is there a way to update all of the rows to go in alphabetical order, then the characters on the end?
Thanks
Here is a way to alphabetize the characters in a column:
select concat((case when col like '%A%' then 'A' else '' end),
(case when col like '%B%' then 'B' else '' end),
. . .
(case when col like '%Z%' then 'Z' else '' end)
) as newcol
from t
Note that this does not handle duplicate letters.
I'm not sure exactly what you mean by "characters on the end". You can use a subquery, for instance, to handle just a subset of them.
Or, if you want to keep everything after the #, something like:
select concat((case when col like '%A%#%' then 'A' else '' end),
(case when col like '%B%#%' then 'B' else '' end),
. . .
(case when col like '%Z%#%' then 'Z' else '' end),
substring(col, locate('#', col) - 1)
) as newcol
from t
I'm wondering if it is possible to exclude a value inside a range defined by "between".
Here is an example:
...
WHEN left(name,2) between 'AA' and 'AZ' then 'HALLO'
...
I want to exclude from this range, for example, the value 'AM'
Is there a short way to obtain this or I need to split the range into two different ones as follow?
...
WHEN left(name,2) between 'AA' and 'AL' then 'HALLO'
WHEN left(name,2) between 'AN' and 'AZ' then 'HALLO'
...
Thanks in advance.
Just put your more restrictive case first:
CASE
WHEN left(name,2) == 'AM' then 'wohoo'
WHEN left(name,2) between 'AA' and 'AZ' then 'HALLO'
END
If it matches 'AM' then since that case is first in the statement, its action will be taken, even though the second case also matches 'AM'.
WHEN left(name,2) between 'AA' and 'AZ' AND NOT left(name,2) = 'AM' then 'HALLO'
You it is possible:
...
WHEN (left(name,2) between 'AA' and 'AZ') AND (left(name,2) <> 'AM')
then 'HALLO'
...