Is there a way to set a field name as a variable in MySQL?
For example:
set #gender = (table_name.gender_column);
select * from table_name
where find_in_set(table_name.gender_column, #gender);
This is exactly how i have tried it but i it returns "Unknown table in field list".
Thanks in advance,
Mike
EDIT: The aim is to use the variables in dynamic crystal report parameters. But what i dont want to do is have to add a new type of gender every time a new one comes along.
E.G. I have 'Male' and 'Female' and am adding 'Trans-gender'. I want the dynamic parameter in Crystal to present the 'Trans-gender' variable in the parameter when it is added to the gender_column. I dont want to have to revisit the multiple queries that use the variable to add 'Trans-gender' to it.
Is there a way to set a field name as a variable in MySQL?
No. SQL doesn't allow variables for schema, table, or column names.
There's a workaround in which you can use text-string processing to create a query, then run it. Something like this may help.
PREPARE query
FROM CONCAT ('select * from table_name',
'where find_in_set(table_name.gender_column, '
#variable,
');'
);
EXEC query;
DEALLOCATE PREPARE query;
This may be a roundabout way of doing what you want. The technical term is "big fat hairball."
Related
I'll start this off by saying I know that there are more practical ways to solve this. It's more of an intellectual curiosity than anything else.
I've inherited a MySQL database where some columns are stored as varchar(5) but actually contain the literals "True" or "False". Changing the structure of the data is not an option right now due to other issues. I'm mapping the columns to an ORM (SQLAlchemy), and I want the column to be mapped to a Boolean data type in the supporting codebase using a type adapter. (I've written this adapter already; it's not the problem.)
To help make the mapping process faster, I'm writing a small query to look at the INFORMATION_SCHEMA table and build a line of Python code defining the column using the ORM's syntax. I cannot assume that the data type varchar(5) is a Boolean column - I need to inspect the contents of that column to see if there are values contained in it besides True and False.
Can I write a query that will both get the column type from INFORMATION_SCHEMA and check the actual values stored in that column?
Here is the query I have so far:
SELECT CONCAT(
"Column(""",
col.column_name,
""", ",
(CASE
WHEN col.DATA_TYPE = "int" THEN "Integer"
-- Code in question
WHEN
col.DATA_TYPE = "varchar"
AND col.CHARACTER_MAXIMUM_LENGTH = 5
AND NOT EXISTS(
-- Doesn't seem to work
SELECT DISTINCT col.COLUMN_NAME
FROM col.TABLE_NAME
WHERE col.COLUMN_NAME NOT IN ("True", "False")
)
THEN "BoolStoredAsVarchar"
WHEN col.DATA_TYPE = "varchar" THEN CONCAT("String(", col.CHARACTER_MAXIMUM_LENGTH, ")")
-- Default if it's not a recognized column type
ELSE col.DATA_TYPE
END),
"),"
) AS alchemy
FROM information_schema.columns AS col
WHERE
col.TABLE_SCHEMA = "my_schema"
AND col.TABLE_NAME = "my_table"
ORDER BY col.ORDINAL_POSITION;
Running this code gives me a permissions error: Error Code: 1142. SELECT command denied to user 'user'#'host' for table 'table_name'. Presumably it's trying to use col.TABLE_NAME as a literal instead of interpreting it.
I've also tried creating a simple stored procedure and making table_name into a variable. However, replacing the FROM clause inside the EXISTS with a variable name gives me a syntax error instead.
Again, it's easy enough to run the query myself to see what's in that column. I'd just like to know if this is possible, and if so, how to do it.
You can't do what you're trying to do in a single query.
The reason is that table names (or any other identifier) must be fixed in the query at the time it is parsed, which is before it has read any values from tables. Thus you can't read the name of a table as a string from information_schema and also read from the table with that name in the same query.
You must read the table name from information_schema and then use that result to format a second query.
This isn't a problem specific to MySQL. It's true of any SQL implementation.
I would like to write a query and allow for a grouping on different colums; for example the end user can group either on country, region, city, or no grouping.
The result is to be used in an ssrs report.
so I would write a query like this:
#value = CASE WHEN #dropdown=1 THEN ', foo.country' ELSE ', foo.region'
#sqlquery = 'select name '+#value+' from foo group by field1'+ #value + ';'
EXEC(#sqlquery);
This does work as expected in management studio (if i define variables and assign something to #dropdown);
I'm a bit at loss on how to implement this in an ssrs report: I want the user to be able to choose no grouping (leave the #value empty)
Visual studio will not be able to 'see' the field and therefore allow to add it in a tablix
Avoid users type the grouping (see the #NeilP recommendation), just create a parameter called Grouping, in Available Values tab you can specify the dropdown selector values.
In the Available Values tab use these settings:
Then in your dataset properties map the SSRS parameter to a T-SQL parameter.
Now you can use #Grouping in your dataset:
set #value = CASE WHEN #Grouping = 1 THEN ', foo.country'
WHEN #Grouping = 2 THEN ', foo.region'
WHEN #Grouping = 3 THEN ', foo.city'
ELSE ''
END
set #sqlquery = 'select name '+#value+' from foo group by field1'+ #value + ';'
The user will be prompt to select one value in the dropdown list:
You can define a default value used in the report, which lets users run the report without specify any value.
Go to Default Values tab in Parameter Properties and add =0 if you want to your report runs without any group by default.
Let me know if this helps.
Try this:
1. Create a parameter GroupBy
Create your data set. Don't directly write your query in to box, use expression instead.
Write your query like this:
I think you probably need to try and adjust your query expression for a while, but it should be the way to go. Good luck.
I would wrap this in a stored procedure and then call that from the dataset
create proc report_1
#value varchar(200)
as
#sqlquery = 'select name '+#value+' from foo group by field1'+ #value + ';'
EXEC(#sqlquery);
Be weary of SQL injection when using dynamic sql, it might be advisable to set a defined list of values for your drop down parameter, either statically or by querying the information schema for column names.
I have a column in MySQL table which has 'messy' data stored as text like this:
**SIZE**
2
2-5
6-25
2-10
26-100
48
50
I want to create a new column "RevTextSize" that rewrites the data in this column to a pre-defined range of values.
If Size=2, then "RevTextSize"= "1-5"
If Size=2-5, then "RevTextSize"= "1-5"
If Size=6-25, then "RevTextSize"="6-25"
...
This is easy to do in Excel, SPSS and other such tools, but how can I do it in the MySQL table?
You can add a column like this:
ALTER TABLE messy_data ADD revtextsize VARCHAR(30);
To populate the column:
UPDATE messy_data
SET revtextsize
= CASE
WHEN size = '2' THEN '1-5'
WHEN size = '2-5' THEN '1-5'
WHEN size = '6-25' THEN '6-25'
ELSE size
END
This is a brute-force approach, identifying each distinct value of size and specifying a replacement.
You could use another SQL statement to help you build the CASE expression
SELECT CONCAT(' WHEN size = ''',d.size,''' THEN ''',d.size,'''') AS stmt
FROM messy_data d
GROUP BY d.size
Save the result from that into your favorite SQL text editor, and hack away at the replacement values. That would speed up the creation of the CASE expression for the statement you need to run to set the revtextsize column (the first statement).
If you want to build something "smarter", that dynamically evaluates the contents of size and makes an intelligent choice, that would be more involved. If was going to do that, I'd do it in the second statement, generating the CASE expression. I'd prefer to review that, befor I run the update statement. I prefer to have the update statement doing something that's easy to understand and easy to explain what it's doing.
Use InStr() to locate "-" in your string and use SUBSTRING(str, pos, len) to get start & End number. Then Use Between clause to build your Case clause.
Hope this will help in building your solution.
Thanks
I'm trying to implement a facebook search in my system (auto suggest while typing).
I've managed to code all the ajax stuff, but I'm not sure how to query the database.
I've created a table called People which contains the fields: ID, FirstName, LastName, MiddleName, Email.
I've also created a FTS-index on all those fields.
I want to create a stored procedure that will get as a parameter the text inserted in the query box and returns the suggestions.
For example, When I will write in the textbox the query "Joh Do"
It will translate to the query:
select * from People where contains(*, '"Joh*"') and contains(*, '"Do*"')
Is there a way to do that in stored procedure?
P.S
I've tried to use the syntax
select * from People where contains(*,'"Joh*" and "Do*"')
but it didn't returned the expected results, probably because it needs to search the words on different fields. Is there a way to fix that?
Thanks.
Try
select *
from People
where (FirstName Like '%'+ #FirstName + '%') and
(MiddleName Like '%'+ #MiddleName + '%') and
(LastName Like '%'+ #LastName + '%')
Also you may want to restrict the results to only return a maximum of say 10 by using:
select top 10
EDIT 1:
OK I now understand the problem better. I would use dynamic sql thus:
First create a split function e.g. Example Split function using XML trick
Then use dynamic sql:
declare #tstr varchar (500)
set #tstr = ''
select #tstr =#tstr + ' Contains(*, ''"'+ val + '*")' + ' and '
from dbo.split(#SearchStr, ' ')
set #tstr = left(#tstr,len(#tstr)-4)
select #tstr
Declare #dsql as varchar(500)
set #dsql = 'select * from People where '+ #tstr
exec (#dsql)
Also please note as per Remus, be aware of SQL Injections, the use of sp_executesql (instead of EXEC) would be better.
The problem is the open list nature of the argument. I can be Joh, it can be Joh Do, it can be Joh Do Na and so on and so forth. You have two main alternatives:
parse the input in the web app (in ASP I assume) and then call an appropriate procedure for the number of entries (ie. exec usp_findSuggestions1 'Joh', exec usp_findSuggestions2 'Joh', 'Do', exec usp_findSuggestions1 'Joh', 'Do', 'Na'). The first procedure uses 1 contains, the second has 2 contains .. and contains ... and the last has 3. This may look totally ugly from a DRY, code design and specially code maintenance pov, but is actually the best solution as far as T-SQL is concerned, due primarily to the plan stability of these queries.
pass the input straight into a single stored procedure, where you can split it into components and build a dynamic T-SQL query with as many contains as necessary.
Both solutions are imperfect. Ultimately, you have two problems, and both have been investigated before to quite some depth:
the problem of passing a list to a T-SQL procedure. See Arrays and Lists in SQL Server 2005 and Beyond
the problem of an undetermined number of conditions in the WHERE clause, see The Curse and Blessings of Dynamic SQL
The AJAX Toolkit has the "AutoComplete" control that provides this functionality out of the box. It is very simple to use.
Look at a sample here
I'm trying to use the prepareStatement function. The code is below. After it executes, it returns me a bunch of vlicense strings instead of the values.
When the code finishing the statement.setString(), the statement becomes:
select 'vlicense' from Vehicle
However, it needs to be:
select vlicense from Vehicle
without the quotation marks. Can anyone tell me what's the problem?
statement = oConnection.prepareStatement("select ? from Vehicle");
String tempString = "vlicense";
statement.setString(1, tempString);
resultSet = statement.executeQuery();
You can't use parameter markers for column names, table names, data type names, or basically anything that isn't data.
When you add a bind variable to a statement like this it is escaped, so that actual SQL string in your example would go to the database as "SELECT 'vlicense' FROM Vehicle', selecting a literal string instead of the column name you want.
You need to concatenate that variable column name into your SQL statement before you prepare it:
statement = oConnection.prepareStatement("SELECT " + vlicense + " FROM Vehicle");
Bind variables are really for query parameters as opposed to dynamic queries.
The ? can't be used to specify the fields, just to do some filters in your query like:
statement = conn.prepareStatement("select field from Vehicle where name=?");
In your case your query is built as:
select 'vlicense' from Vehicle
which means: GET ME A STRING 'vlicense' FOR EACH RECORD OF 'Vehicle'. And you'll get n repeated strings depending on the number of records in your table
It has nothing to do with jdbc, prepared-statements or mysql.
It's just a wrong sql statement.
If you type:
Select 'justanexample' from Vehicle
and the table contains 4 lines, you will get 4 times
'justanexample'
'justanexample'
'justanexample'
'justanexample'
as result.
You did not specify your the table structure, but I guess the
statement should somehow look like this:
select * from Vehicle where license = ?