In an SSRS report I'm building, I've a query like the one below:
SELECT ID, Name
FROM TableA
WHERE Name IN (#name)
And then within SSRS, I have the parameter available values set to 'Get values from a query' and the Value field will be something like below:
'A','B','C'
'D','E','F'
'G','H','I'
And the Label field something like this:
Label A
Label B
Label C
When I run the query
SELECT ID, Name
FROM TableA,
WHERE Name IN ('A','B','C')
The correct results are returned in SQL Management Studio, however, the report returns nothing. How do I get the correctly formatted value into the IN statement?
Based on your example, I would approach it like this...
Create a table or view that contains your labels and values such as
myTable:
myCaption MyValue
'Label A' 'A'
'Label A' 'B'
'Label A' 'C'
'Label B' 'D'
'Label B' 'E'
'Label B' 'F'
'Label C' 'G'
'Label C' 'H'
'Label C' 'I'
For your first parameter (#myLabel), the dataset would simply be
SELECT DISTINCT myCaption FROM myTable ORDER BY myCaption
The your second parmameter (#myValues) (assuming you want the user to be able to choose from the values) would be
SELECT myValue FROM myTable WHERE myLabel = #myLabel
You will need to make the parameter multi-value and set the available values to the 2nd dataset, optionally you can set the default values to the same dataset.
In your main report dataset the query would be like your example
SELECT * FROM myDataTable WHERE myColumn IN (#myValues)
As long as the above is directly in the dataset query (in other words, you are not using a stored procedure), then this will work as expected. SSRS will automatically convert your multi-value parameter into a comma separated list and inject it into your dataset query so the actual query sent to the server would be SELECT * FROM myDataTable WHERE myColumn IN ('A', 'B', 'C')
Related
I'm using SSRS.
I have one parameters, it is a list where I can select multiple values.
The Available values came from a query that gave something like this (example data):
Value_Field
Label_Field
0
Apple
1
Banana
2
Apple tee
So, in my report, I can select one or multiple values.
What I want to do is when the user use my report, I want the default values to be all the values that begin with A.
In this example, I want Apple and Apple tee to be selected everytime an user open my report.
I tried to use the regex, but no succes.
Any idea?
Assuming your parameter dataset query for the available values is the following
SELECT Value_Field, Label_Field
FROM mytable
You have to create a second dataset with the filter and set it as your parameter default values
SELECT Value_Field, Label_Field
FROM mytable
WHERE Label_Field LIKE 'A%'
I usually put my values in a temp table and add a Default Value column that has the Available value when it matches. Then I update the other Default Values with another available value.
DECLARE #SEARCH VARCHAR(20) = 'A'
SELECT *,
IIF(Label_Field LIKE #SEARCH + '%', Label_Field, '') AS DEFAULT_VALUE
INTO #TEMP_VALUES
FROM CURRENT_QUERY
UPDATE #TEMP_VALUES
SET DEFAULT_VALUE = (SELECT MAX(DEFAULT_VALUE) FROM #TEMP_VALUES
WHERE DEFAULT_VALUE = ''
SELECT * FROM #TEMP_VALUES
I used a parameter for the search value to make it easy to change if necessary. If it may change, you can add it as a hidden parameter on the report so you can change it easily when needed.
Database is MySQL 5.6
CREATE TABLE set_t
(
set_r SET ('a', 'b', 'c')
);
INSERT INTO set_t (set_r) VALUES ('a,b,c'), ('a,b');
In my case i know only 'a' and 'b'.
For example, need to select row where set_r is "a,b,c".
Value 'c' is unknown, cant use it in query.
Values order is unknown also. They are may be set_r SET ('c', 'b', 'a') or else.
How to select rows, which contains unknown values?
The easy way to do it for your sample data is with NOT IN:
SELECT *
FROM set_t
WHERE set_r NOT IN ('a', 'b', 'a,b')
But this does not scale well if you have larger set and you want to include more members than a and b in the list of known members.
Every member of a set is stored as a numeric value.
In your set the numeric values are:
SET Member Decimal Value Binary Value
'a' 1 001
'b' 2 010
'c' 4 100
So, a value like 'a,b' is stored as 3 (Binary 011)
and a value like 'a,b,c' is stored as 7 (Binary 111)
If you know the numeric values of the known members, which you can get by the order they are defined in the set, then you can use bit operations to get what you want:
SELECT *
FROM set_t
WHERE set_r | 3 <> 3 -- 3 is the numeric value of 'a,b'
or:
SELECT *
FROM set_t
WHERE set_r | 0b11 <> 0b11 -- 0b11 is the numeric binary value of 'a,b'
See the demo.
You can use find_in_set() to check for individual values. See SET documentation here
select * from set_t where find_in_set('a', set_r) and find_in_set('b', set_r)
This gives you
set_r
(a,b,c)
(a,b)
See this db<>fiddle
If you don't want the second row, you can add and not like 'a,b'.
The most efficient method is to use the binary comparisons. This assumes that you know the position of 'a' and 'b' in the set:
select *
from set_t
where (set_r | b'11') <> b'11';
You can also do this using string operations. This is a bit of a pain, because you need to handle the comma delimiter:
select *
from set_t
where replace(replace(replace(concat(',', set_r, ','), ',a,', ','), ',b,', ','), ',', '') <> ''
The logic is:
Put delimiters at the beginning and end of set_r.
Remove delimited elements, replacing them with the delimiter.
Check if the result only has delimiters.
This version works regardless of the size of the set and the position of the elements you want to compare against.
Here is a db<>fiddle.
Use-Case: I want to select all entries from table t123, where field 'text' of the table is NOT a subset string of 'text_target'.
For example:
text_target = 'abf'
t123 has entries like,
name text
1) record1 abc
2) record2 abd
3) record3 af
result should be records 1 and 2, since their 'text' field is not subset of text_target value 'abf'.
EDIT: corrected the question
use like
select * from t123 where text like'ab%'
I think you'll need to explode the string:
where ( (test like '%a%') +
(test like '%b%') +
(test like '%f%')
) <> length(test)
It is not obvious that even regular expressions can help.
However, looking at strings as sets with one element per letter sounds like a data modeling problem. You may want to ask another question describing your data and suggestions on how you might design your database.
Here is a rextester (thanks to Tim).
Not elegant, but I suppose:
select *
from t123
where not ( substring( text from 1 for 1 ) in ( 'a', 'b', 'f', ' ' )
and substring( text from 2 for 1 ) in ( 'a', 'b', 'f', ' ' )
and substring( text from 3 for 1 ) in ( 'a', 'b', 'f', ' ' ) )
could return those rows that contain other letters.
Use regular expression. For instance, if we suppose that you want to retrieve records NOT containing characters from "text_target" ("abf") :
SELECT * FROM t123 WHERE NOT text RLIKE "a|b|f"
I have a table which has one column of addresses. I have some 10 - 11 places name.
When i query that table using 'Select * ...', i want to create a new column which matches the values with address fields and store that values into new column of exist else 'Not Found'.
The table has address column as below. I want to extract areas from it such as BTM Layot, Wilson Garden
When i do the select query, the output should be that address field and one more field which will give me the abstract location area from address field. And if any value does not matches the address field then it shoud display as 'Area Nt Specified'
Consider a cross join query (query with no joins but a list of tables in FROM clause) between the larger table of addresses (t1) and smaller table of your 10-11 places (t2) holding BTM Layot, Wilson Garden... values. This will be scalable instead of manually entering/editing places in an IN clause.
Then use a LIKE expression in a WHERE clause to match the places which are a part of the larger address string. However, to return all original address values with matched places use the LEFT JOIN...NOT NULL query with cross join as derived table (sub).
SELECT `maintable`.`address`, IFNULL(sub.`place`, 'Area Nt Specified') As matchplaces
FROM `maintable`
LEFT JOIN
(SELECT t1.ID, t1.address, t2.place
FROM `maintable` As t1,
(SELECT `place` FROM `placestable`) As t2
WHERE t1.address LIKE Concat('%',t2.place,'%')) As sub
ON `maintable`.ID = sub.ID
WHERE `maintable`.ID IS NOT NULL;
If really need to use regular expression, replace the LIKE expression in derived table with below:
WHERE t1.address regexp t2.place
If you have a list of know places, then you can do:
select (case when address regexp '(, BTM Layout|, Bapuji Nagar|, Adugodi)$'
then substring_index(address, ', ', -1)
else 'Not Found'
end)
You can expand the regular expression to include as many places as you like.
Or alternatively, you don't really need a regular expression:
select (case when substring_index(address, ', ', -1) in ('BTM Layout', 'Bapuji Nagar', 'Adugodi', . . .)
then substring_index(address, ', ', -1)
else 'Not Found'
end)
I'm trying to separate one column that contains a blood type into two columns.
For example, if my value is ABNG in the existing blood type column, I want to separate this into two new columns and insert the values: AB and Neg.
Not sure if a case statement will handle this, but I tried different variations and could not find a solution.
Here is what the existing data looks like, there are 9 blood types (including the Unknown which is fine) with some bad data mixed in (' ', 0, and B).
Without having the best grasp on how to handle this I am thinking a view could be created that would split the information into new columns.
And this is what I'm hoping the end result to be:
Is this possible?
You can use CASE statement for checking conditions and wildcard characters for string filtration for the source column.
SELECT PBTYPE [Existing Blood Type],
CASE
WHEN PBTYPE LIKE 'O%' THEN 'O'
WHEN LEFT(PBTYPE,1)='A' AND SUBSTRING(PBTYPE,2,1)<>'B' THEN 'A'
WHEN LEFT(PBTYPE,2)='AB' AND SUBSTRING(PBTYPE,2,1)='B' THEN 'AB'
WHEN PBTYPE LIKE 'B%' THEN 'B'
WHEN PBTYPE = 'UNK' THEN 'UNK'
END [Blood Type],
CASE
WHEN PBTYPE LIKE '%POS' OR PBTYPE LIKE '%PS' THEN 'POS'
WHEN PBTYPE LIKE '%NEG' OR PBTYPE LIKE '%NG' THEN 'NEG'
WHEN PBTYPE LIKE '%B' THEN 'B'
WHEN PBTYPE LIKE '%UNK' THEN 'UNK'
END [Rho]
FROM YOURTABLE
WHERE PBTYPE <> '' AND PBTYPE <> '0'
Click here to view result
Given that there's a limited number of blood types (and hoping that your data is formatted well), you could do something like:
SELECT Type = CASE WHEN col LIKE 'AB%' THEN 'AB' /*gets AB*/
ELSE LEFT(col, 1) /*gets o,a,or b*/ END,
Valence = RIGHT(col, 3) /*gets pos or neg*/