Set MySQL Column Alias to a Calculated Date - mysql

I'm looking to do something like this:
select data AS curdate() from table;
so the resulting table would look like:
2013-04-26
data 1
data 2
data 3
I can't figure out the syntax, but it must be possible?
I've tried it without quotes of any kind, which returns an error. Single quotes and back ticks both return the SQL itself as the column header.

That's an unusual requirement, but if you insist, you'd have to use dynamic sql.
SET #curdate = CURDATE();
SET #sql = CONCAT('SELECT whatever AS "', #curdate, '" FROM whatever');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

An alias is considered an identifier and cannot be assigned to a function without the use of dynamic SQL. It would break referencing such as:
SELECT *
FROM (SELECT 1 AS curdate()) a

Related

Error while creating a view with procedure MySQL

I have a problem when I try to create a view using a procedure. I have to do that because I need to make a pivot in MySQL, converting rows of a table in columns of another.
The query works great, but when I put it in the "CREATE VIEW" statement it gives me error.
Here is the query with CREATE view
CREATE VIEW `Untitled` AS
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(formazioni_persone.id_formazione = ',
formazioni.id,
', true, false)) AS "',
formazioni.titolo,'"'
)
) INTO #sql
FROM formazioni;
SET #sql = CONCAT('SELECT persone.*, ', #sql, ' FROM persone INNER JOIN formazioni_persone ON persone.id = formazioni_persone.id_persona GROUP BY persone.id');
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
The query without CREATE VIEW Untitled AS works great
The query without CREATE VIEW Untitled AS works great. I already tried to create a TEMP TABLE inside the CREATE VIEW, but nothing. Also tried to use delimiters like that, but nothing
DELIMITER $$
CREATE VIEW `Untitled` AS
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(formazioni_persone.id_formazione = ',
formazioni.id,
', true, false)) AS "',
formazioni.titolo,'"'
)
) INTO #sql
FROM formazioni;
SET #sql = CONCAT('SELECT persone.*, ', #sql, ' FROM persone INNER JOIN formazioni_persone ON persone.id = formazioni_persone.id_persona GROUP BY persone.id');
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
END $$
DELIMITER ;
Error: 1064 - 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 'SET #sql = NULL' at line 2, Time: 0.082000s
A VIEW is not a procedure. A VIEW is only a single SELECT statement, which must have fixed columns at the time you define the VIEW. You can't make a VIEW that is also a procedure.
Sorry, if you need a pivot-table, you need to specify the values for each column in the query. You can't make a SELECT query or a VIEW that dynamically adds more columns as it finds potential future values.
And you can't define a VIEW that runs an arbitrary block of procedure code anyway. That would require a procedure.
You should just use the solutions that are already shown in questions like MySQL - Rows to Columns
There are no other shortcuts or workarounds.
By the way, all SQL databases have this restriction, not just MySQL.
Re your question:
I'm looking for a solution that doesn't require manual update of the query
A pivot-table query must have as many columns in the select-list as the number of columns you want it to return. There is no way to make an SQL query that expands the number of columns dynamically as a result of the data it reads at execute time.
The only way you can make a single query that returns all the data is to NOT do a pivot-table query, and instead return all the data in rows, not columns.
SELECT p.*, f.titolo, pf.id_persona IS NOT NULL AS ha_formazioni
FROM persone AS p
CROSS JOIN formazioni AS f
LEFT OUTER JOIN formazioni_persone AS fp ON fp.id_formazioni AND fp.id_persona = p.id
This will return one row for each formazioni per persone. Then you must write code in your application to loop over all the rows of the reesult, and format the data in columns in the manner you want.

How to set a local list/tuple variable in mysql

Is there a way to do the following in mysql?
SET #studios = ('Disney', 'Warner Bros.', 'Fox');
SELECT * FROM movies WHERE provider IN #studios;
When I try doing the above I get the error:
Operand should contain 1 column(s)
The error is coming from your initial assignment. You cannot assign lists to variables.
The only way of doing this in MySQL is to either create a temp table to hold the values, and then do ... IN (SELECT someVal FROM thatTemp), or to dynamically create the query with the values directly in the query string.
Example temp table creation:
CREATE TEMPORARY TABLE `someTemp` ( someVal VARCHAR(16) );
INSERT INTO `someTemp` (someVal) VALUES ('a'), ('b'), ('c');
SELECT * FROM myTable WHERE myField IN (SELECT someVal FROM someTemp);
DELETE TEMPORARY TABLE `someTemp`;
Alternatively, there is also FIND_IN_SET, which could be used like this:
SET #list = 'a,b,c';
SELECT * FROM myTable WHERE FIND_IN_SET(myField, #list) <> 0;
but this method probably has extremely poor performance (and may not be useable if your "myField" values may contain commas).
It is not possible to set a tuple/list/array in a user-defined variable in MySQL. You can use Dynamic SQL for the same:
-- we use single quotes two times to escape it
SET #studios = '(''Disney'', ''Warner Bros.'', ''Fox'')';
-- generate the query string
SET #query = CONCAT('SELECT * FROM movies WHERE provider IN ', #studios);
-- prepare the query
PREPARE stmt FROM #query;
-- execute it
EXECUTE stmt;
-- deallocate it
DEALLOCATE PREPARE stmt;
You could concatenate your list to a string, and use FIND_IN_SET as your criteria. Might not be super efficient, but makes the code quite easy to read and maintain.
Looks like this:
SET #studios = CONCAT_WS(',',
'Disney',
'Warner Bros.',
'Fox'
);
SELECT * FROM movies
WHERE FIND_IN_SET(provider, #studios) <> 0;

how to configure the table at runtime in mysql query

people know that we can use if statement to configure a query in the select statement like this
select if(var=1,amount,amount/2) from mytable;
But what if I want to achieve something like this:
select amount from if(var=1,mytable1,mytable2);
Is there any way to configure the table at run time?
SELECT amount FROM mytable1 WHERE #var = 1
UNION
SELECT amount FROM mytable2 WHERE #var = 0
UPD: Here's what MySQL EXPLAIN looks like for the part of the query which has a condition evaluating to FALSE:
Note the Impossible WHERE part. MySQL recognizes that the expression in WHERE is constantly evaluating to FALSE, so it doesn't even try executing the query. Hence, no performance overhead when using this approach.
(Upgrading to an answer)
Where did var come from?
If it's a variable in another language, you could test it in that other language and then construct different SQL as appropriate:
$sql = "SELECT amount FROM " . ($var = 1 ? "mytable1" : "mytable2");
If it's a user variable in SQL, you could similarly use an IF statement around the two alternative SELECT statements:
DELIMITER ;;
IF #var = 1 THEN
SELECT amount FROM mytable1;
ELSE
SELECT amount FROM mytable2;
END IF;;
DELIMITER ;
If it's anything else (like a field from your tables), then your question doesn't make a great deal of sense.
Based on the mysql manual pages, it appears you cannot do this with the traditional syntax.
"User variables are intended to provide data values. They cannot be used directly in an SQL statement as an identifier or as part of an identifier, such as in contexts where a table or database name is expected, or as a reserved word such as SELECT."
- [http://dev.mysql.com/doc/refman/5.6/en/user-variables.html][1]
The exception to this is that you can assemble a prepared statement, but is probably not a better solution for most programming tasks. It would be better to leave the sql string generation to the language invoking mysql.
But, if you are doing this as part of a "sql only" task, like an import, this seems to be the approach you must take.
SET #s = CONCAT("SELECT * FROM ", if(true, "table1", "table2"), " LIMIT 1");
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #s = CONCAT("SELECT * FROM ", if(false, "table1", "table2"), " LIMIT 1");
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Need help with MySQL query

I am trying to execute the following query statement contained within a Stored Procedure -
Where all P... are parameters to SP (ex PInitialDateFrom).
SET #stmt_text = CONCAT('SELECT AccountID, Firstname as ClientName, EmailID
, ProductID, InitialPurchaseDate as Purchasedate
FROM client_account
WHERE IsRemoved = 0
AND (InitialPurchasedate between ? and ?)
AND ProductId IN (?)');
PREPARE stmt FROM #stmt_text;
SET #initDt1=PInitialDateFrom, #initDt2 = PInitialDateTo, #inlist=PIDs
, #stmt_text = null;
EXECUTE stmt USING #initDt1, #initDt2, #inlist;
DEALLOCATE PREPARE stmt;
I am passing PID's as a string of ids like 1,2,3
When I try to execute the statement, only the first id is considered. For ex. 1,2,3 is used only 1 is taken, if 3,2,1 is used only 3 is taken.
Can anybody tell what's wrong with this query?
You can't use this part:
and ProductId in (?)
Remember: SQL parameters are not like C macros where you are just doing string replacements. They are more than thar: When you use ?, one and only one parameter gets bound. So, when you try to bind 1,2,3 to that parameter, it's not like you are trying to bind three values but only one.
If your list is going to be of fixed size, you could use:
and ProductId in (?,?,?)
Otherwise, I don't think you will be able to use parameters for that clause. Maybe doing something like:
set #initDt1=PInitialDateFrom,
#initDt2 = PInitialDateTo,
#inlist=PIDs,
#stmt_text = null;
set #stmt_text =
concat('Select AccountID, Firstname as ClientName, EmailID, ProductID
, InitialPurchaseDate as Purchasedate from client_account
where IsRemoved=0 and (InitialPurchasedate between ? and ?)
and ProductId in (', #inlist, ')');
prepare stmt from #stmt_text;
execute stmt using #initDt1, #initDt2;
deallocate prepare stmt;
Make sure you sanitize your input for PIDs so you don't add SQLInjection vulnerabilities to your code.
You should put it like this:
and ProductID = (?)
I hope it works.

convert mysql stored procedure to mssql

I need to used dynamic order query in mysql and i have successfully achieved that through string concatenation in mysql as follows:
set #stmt_text := concat('select * from abc order by ',sorder);
prepare stmt_handle from #stmt_text;
execute stmt_handle;
deallocate prepare stmt_handle;
i need a similar way to convert this in mssql
Any ideas??
Yes, just run it like this:
execute ('select * from abc order by ' + #sorder);
But don't forget that you need to verify the sorder variable if you get it through user input (to stop sql-injections)