flow control in MYSQL - mysql

I am trying to convert a SQL Server query to MYSQL, but am having trouble with the IF statements. In the SQL Server version, they are used to direct the flow of the query based on a flag, but I cannot get it to work in MYSQL. I have outlined how the code works below:
The script sets a flag based upon how much data can be matched between the query and the database.
It then performs a select statement based upon the flag: if flag=1 select a,b,c where match logic
else if flag=2 select d,e,f where different match logic
I have tried using both IF and CASE WHEN, neither of which work. I would normally have put the IF within the WHERE clause, but different columns are selected depending upon the flag.
Is there a function that will perform IF/ELSE flows MYSQL?
Any help would be greatly appreciated!

Assuming the types and number of columns are compatible, you could do:
select a, b, c
from t
where (v_flag = 1) and match_condition_1
union all
select d, e, f
from t
where (v_flag = 2) and match_condition_2;
The alternative is to use a stored procedure. In MySQL, the if control flow statement is only allowed in programming blocks -- stored procedures, stored functions, and trigger.

Related

How to declare a variable within the same statement in MySQL?

How do I create variables in MySQL that I can refer to in the same statement?
Does this work for UPDATE and INSERT statements as well?
I asked this because I got a lot of SQL text files where I execute single commands using Ctrl-Enter from MySQL-Workbench. If it would be multiple statements I would have to select the commands to execute before pressing Ctrl-Enter. This is more complex and error-prone.
Before someone asks: this is a private database with single user and I use these scripts to modify data directly where editing through the GUI would take ages.
I just decided that I should wrap more complex code with a java program. This was a good decision. Still I need the solution to this question for less complex problems where I don't want to write java code.
It's not clear why you need to do this in the same statement. It's easy to run two statements, and it makes the code much easier to write and easier to understand. You should always consider how the developer who succeeds you working on your code is going to understand and maintain it.
SET #variable = 'Value';
SELECT ... FROM your_table WHERE a_column = #variable;
If you do need to do it in one statement, I'd do it this way:
SELECT ... FROM your_table
CROSS JOIN (SELECT #variable := 'Value') AS _init
WHERE a_column = #variable;
By doing this in a derived-table, it only does the assignment once. If you do it in the select-list as you showed in your solution, it does the assignment as many times as the number of rows returned by the inner query. This is not a big deal if the assignment is for a constant value, but if your variable is assigned the result of a costly expression, it will be slow.
Well I wasn't able to find a solution on the web. But it turned out to be... fairly straightforward.
Just create a statement that wraps your statement:
select *, #variable:='Value' from (
select * from your_table inner where #variable=inner.column
) as outer

Error running SQL in MS-Access with ODBC connection to MYSQL

I was helping a non-profit migrate MS-Access data to MYSQL. So, I ported data to MYSQL and created links in ms-access to MYSQL tables using ODBC. Majority of the existing SQL works fine. However I am stumped on this one error -
You have an error in your SQL syntax check the manual that corresponds to your MySQL server version for the right syntax to use near UNION...
I have stripped the SQL with 7 UNIONS to bare bones where it still fails.
(SELECT 1 as A FROM Households H)
UNION ALL
(SELECT 2 as A FROM Households H)
UNION ALL
(SELECT 3 as A FROM Households H)
The part that is getting to me is that I am able to run above successfully as long as I run only one UNION meaning below SQL, but the moment I add a third one, it gives ODBC error
(SELECT 1 as A FROM Households H)
UNION ALL
(SELECT 2 as A FROM Households H)
I tried using ` or ' or [] but none of these helped. The reason I am frustrated with this error is that either it should fail with all or none, it gives an error only when using two or more UNION clauses. Could this be a potential bug in driver?
I am using mysql-64 bit on win-7 64bit with ms-access and a 32-bit driver. It shouldn't be an architecture problem as I am able to run other queries with multiple UNIONs, and accessing the same set of tables.
It would be great if someone can give pointers on how to debug this further.
In my version of Access, when I edit a query in Design (SQL) view there are three buttons at the top. "Union", "Pass-Through", and "Data Definition".
If I click "Pass-Through" your query works. If I click "Union" it breaks. Can you get away with using "Pass-Through" for this query?
Even in "Union" or "Data Definition" mode, this seems to work:
(SELECT 1, column1 as A FROM Households H)
UNION ALL
(SELECT 2, column2 as A FROM Households H)
UNION ALL
(SELECT 3, column3 as A FROM Households H);
Maybe Access is confused by only a single column?
Alternatively, just use a a multiplex table instead of a union:
SELECT mux.id,
IIf(mux.id=1,column1,IIf(mux.id=2,column2,column3)) AS A
FROM Households, mux;
Note: mux table should have 3 values in it 1,2,3. If it has more, you'd want to limit to the first 3 (or n) in a where clause.
It is a known MySQL problem: more than two UNION SELECT statement problem (with MS Access) but I don't know if the problem is in the MSAccess SQL parser (which compiles to ODBC SQL), or in the MySQL ODBC driver (which compiles ODBC SQL to MySQL SQL)
To work it out, I'd have to look at the ODBC log, and the ODBC specification, and see if Access was emmitting valid ODBC SQL.
That would be a waste of effort, since it makes more sense to use a pass-through query anyway. The main reason for using a native MSAccess query in this place would be to join to different data sources - for example, an Excel Spreadsheet and a MySQL table -, and according to the comments on the MySQL bug report, the problem goes away when you do that.
I am not sure about where the problem lies, but I think (though it's only an assumption) that this is on MS Access side. I had two UNION queries, each of them was putting some other queries together. Both used somewhat complicated sub-queries so I had lots of problem to create a pass-through query and I didn't want to use MySQL "views".
Surprisingly one of my queries worked, the other showed an error. My idea is that the working query used some Access features while the other was some kind of SELECT ... FROM's .
I don't know the rules but I think that when your query is simple, Access sends it to external database engine and puts one more bracket and causes an error. If you do a comlicated query, Access gets all data it needs and makes all necessary operations itself. For example, you may try to create a pivot query, that uses MSSQL TRANSFORM statement, which does not exist in MySQL, so it is obvious that Access handles it itself. So why couldn't it make SELECT by itself? I don't know. Maybe some performance reasons?
My working query differed from the other that it had one more (string) field that was calculated by built-in Access function. It used also Access & operator, which has another meaning (logical AND) in MySQL. (By the way to join strings in MySQL use CONCAT function). They of course need to be evaluated by Access, because MySQL does not understand this method of joining strings together.
I suggest just to make UNION not from tables, but from queries (like SELECT * FROM tablename and nothing more) and giving them a field that you don't need but that will force Access to handle the query. So a query (in Access) should look like this:
SELECT tablename.*, [somefield1]&[somefield2] AS useless_field FROM tablename;
(in my Access 2000 operations like "a" & "b" or IIf(true;true;false) were probably simplified and solved, so it didn't work. I think one needs at least one dynamic field to evaluate. I also did no performance tests. Probably it would be fastest if you add to integers, maybe just increase your index by 1?).
Then, of course, you join it together:
SELECT * FROM query1
UNION ALL
SELECT * FROM query2
UNION ALL
SELECT * FROM query3
UNION ALL
...
SELECT * FROM queryn
;
You don't need this useless_field of course.
I agree that this is a workaround but I have no other ideas.

Stored Procedures and SSRS 2008

I have a stored procedure in SQL Server 2008 that consists of multple select statements. When building a report in SSRS, I have a dataset that uses that stored procedure. However, the only fields that show up are the ones that are in the first select statement. Is there a way to show the other fields or use multiple select statements within one stored procedure?
Thanks!
Do the selects output the same schema (i.e. fields)? If so, and if you need all the results, you could try UNIONing the separate queries together. Otherwise, why not move the query you need into a new stored proc and call that from the report?
Eric, it's been my experience that when SSRS is based on a stored procdure, the results of the last Select statement are used and not the first. So you should be able to do anything you want up until the last Select statement in the stored proc and then make sure the last Select contains the correct data/columns for the report.
From the MSDN documentation
If multiple result sets are retrieved
through a single query, only the first
result set is processed, and all other
result sets are ignored. For example,
when you run the following query in
the text-based query designer, only
the result set for Production.Product
appears in the result pane:
SELECT ProductID FROM Production.Product
GO
SELECT ContactID FROM Person.Contact

Inline table-valued function vs Stored Procedure (SQL Server)

I'm a bit confused about what is better to use in the following case:
I have a quite complex query that is used for reporting purposes. A simplified version looks like
SELECT [type], COUNT(*) as total_num, COUNT(DISTINCT user_id) as uq_user_num
FROM table1
INNER JOIN table2 ON (...)
...
WHERE table3.last_action_date BETWEEN :start_date AND :end_date
GROUP BY [type]
I can create an inline function or a stored procedure that takes start_date and end_parameters and executes this query.
I incline to function because this task does not involve any data modification or complex logic. Also, I may want to use the result in APPLY later (it's not really important at the moment).
Does it make sense to use function, not procedure? Is it any difference from performance point of view (execution plan caching, etc) ?
Thank you.
Using a multi-statement table valued function is similar to using a proc from plan caching and cached plan reuse perspective.. Using an inline table valued function is similar to using a view from the plan cache and plan reuse perspective(reuse only happen is exact same statement is used. ie same parameters).
Considering the same you should use a multi-statement table valued function.
You may want to consider using a View too. A view is efficient if the results do no change given the parameters provided, which is what you have here. In this case, the results will not change if you make two calls with the same start and end date.
However, two of the main differences between a stored proc and a function are that you cannot call updates/ inserts from a function and you cannot call a stored proc as part of a select statement, but you can with a function.
See this thread for more info:
Function vs. Stored Procedure in SQL Server

SELECT-ing data from stored procedures

I have a complicated SELECT query that filters on a time range, and I want this time range (start and end dates) to be specifiable using user-supplied parameters. So I can use a stored procedure to do this, and the return is a multiple-row result set. The problem I'm having is how to deal with this result set afterwards. I can't do something like:
SELECT * FROM (CALL stored_procedure(start_time, end_time))
even though the stored procedure is just a SELECT that takes parameters. Server-side prepared statement also don't work (and they're not persistent either).
Some suggest using temporary tables; the reason that's not an ideal solution is that 1) I don't want to specify the table schema and it seems that you have to, and 2) the lifetime of the temporary table would only be limited to a invocation of the query, it doesn't need to persist beyond that.
So to recap, I want something like a persistent prepared statement server-side, whose return is a result set that MySQL can manipulate as if it was a subquery. Any ideas? Thanks.
By the way, I'm using MySQL 5.0. I know it's a pretty old version, but this feature doesn't seem to exist in any more recent version. I'm not sure whether SELECT-ing from a stored procedure is possible in other SQL engines; switching is not an option at the moment, but I'd like to know whether it's possible anyway, in case we decide to switch in the future.
Selecting from functions is possible in other engines. For instance, Oracle allows you to write a function that returns a table of user defined type. You can define result sets in the function, fill them by using queries or even using a combination of selects and code. Eventually, the result set can be returned from the function, and you can continue to query on that by using:
select * from table(FunctionToBeCalls(parameters));
The only disadvantage, is that this result set is not indexed, so it might be slow if the function is used within a complex query.
In MySQL nothing like this is possible. There is no way to use a result set from a procedure directly in a select query. You can return single values from a function and you can use OUT or INOUT parameters to you procedure to return values from.
But entire result sets is not possible. Filling a temporary table within you procedure is the closest you will get.