Where conditions on top of existing sql - alias columns - mysql

I am trying to add dynamic filter conditions to existing sql query, I wrapped the query like:
select *
from ( existing sql )
where 1=1 <adding conditions here based on user selection>
In the existing sql I have alias columns on which I am not able to do the query's, can anyone let me know how to do it.
Sample eg:
select *
from (select firstName as "FN", lastName as "LN", city as "c"
from users
)
WHERE 1 = 1 and FN IN ('John');
This is not working, as adding filter on alias column ends in error.
If I dont have alias column in double quotes then its working fine. But I am in need to wrap the existing query and do condition on top of it.

You need an alias for the derived table:
select *
from (select firstName as "FN", lastName as "LN", city as "c"
from users
) x
-------^
WHERE 1 = 1 and FN IN ('John');
Note that in MySQL, derived tables are usually materialized. This can have a big impact on performance, particularly if your query depends on indexes. This route is a bit dangerous from a performance perspective.
Also, your use of in is equivalent to =. The latter is more specific.

Related

SQL Query when where clause could be empty or contain value

I would like a select query that would be able to select a value that may or may not be present in the where clause. Schema:
----------------------------------
studentid|firstname|lastname|major
My select clause would be
select * from students where studentid?={param} AND firstname?={param} AND lastname?={param} AND major?={param};
I put a question mark because I mean to say I could pass a value in the where clause or I might not. It could be
select * from students where studentid?=34344 AND firstname?="john" AND lastname?="smith" AND major?="";
select * from students where studentid?=34344 AND firstname?="john" AND lastname?="smith" AND major?="english";
Is there a way to do this easily without a stored procedure?
You can do that by using variables and checking null like this:
Declare #StudentId nvarchar(100) --can be null or evaluated
select * from students
where (#StudentId is null or studnetId= #StudentId) AND -- for other properties as well
Another option is using dynamic sql and first you have to build your sql query and then execute it (I don't like it)
You can handle it in the application side if possible:
string query= "select * from students where 1=1 /*trick for adding more conditions*/"
if(numberId is not null)
query += "AND studentId= {numberId} ";
//for other conditions ...

Running a SQL SELECT statement against a MYSQL column of SET type

I'm trying to run a SQL SELECT statement against a column that is of type SET. The table is called myTable and the columns in myTable are called base_props and names. The base_props column is of type SET. The values in base_prop are vb,nt, cnt,poss and loc. So I would like to SELECT entries from the column 'name' where base_props have both the values, vb and poss. The results I'm looking to get may have values other than just vb and poss. So to be clear I would like to select all entries that have the values vb and poss regardless if they have other values as well. I've tried the following SQL queries but I can't get the desired results.
SELECT name from myTable WHERE base_props = 'vb' AND base_props = 'poss'
That query returns an empty result set. I've tried using FIND_IN_SET() and IN() but I couldn't get anywhere with that. I've written SQL statements before but never had to deal with columns that are type SET. Any help is appreciated.
The only thing I can come up with is using the LIKE keyword:
SELECT name FROM myTable WHERE (base_props LIKE '%vb%' AND base_props LIKE '%poss%');
This will make sure both vb and cnt are in the base_props column. Of course you can use cnt, nt and loc in there, or any number of base_props values in the sql, just add more AND statements.
OR as a deleted answer by samitha pointed out, you can use FIND_IN_SET:
SELECT name from myTable WHERE FIND_IN_SET('vb', base_props) AND FIND_IN_SET('poss', base_props);
Comment (by spencer7593): "both of these work, but there is a slight difference. The LIKE operator will actually match any member that includes the search string anywhere in a term; the FIND_IN_SET function will only match an exact member. It's also possible to search for members in set by the order they appear in the SET definition, using the MySQL BITAND operator: for example, to match the 1st and 4th members of the set: WHERE base_props & 1 AND base_props & 8". So for example, if you have 'a' and 'aaa' in your set, then using the LIKE "%a%" method will also return rows containing 'aaa'.
Conclusion: use the FIND_IN_SET solution since it will work for all cases.
FIND_IN_SET return index, Try this
SELECT name from myTable WHERE FIND_IN_SET(base_props, 'vb') > 0 AND
FIND_IN_SET(base_props, 'poss') > 0

Defining aliases in a statistical query

I need to do:
SELECT COUNT(*)
FROM some_table
WHERE someAlias1 = someValue1
AND someAlias2 = someValue2;
someAlias is an alias for a column in some_table. In my case I can't name the columns directly; I need to use aliases.
The issue is that I only know about defining aliases inside the select clause which I don't see how I can do in this case.
Is there a way to accomplish what I need in this case?
edit: Why do I need aliases? I'm building a query from alternative parts, and the condition above applies to different columns from different tables, but with the same logical role. So I need a way to relate to different alternative columns with the same name.
I will appreciate if you answer this question only if you know an answer, even if you don't understand why may I need an alias
You could do a nested SELECT statement then draw the count out from the inner query, I don't really see a way to escape using the column names
SELECT COUNT(*)
FROM(
SELECT col1 as someAlias1,
col2 as someAlias2
FROM some_table
WHERE someAlias1 = someValue1
AND someAlias2 = someValue2
) as inner
I can't figure out a scenario where you can't name the columns directly. If the column name is duplicated, prepend the table name:
WHERE someTable1.someColumn1 = someValue1
If the column name is a reserved keyword or contains spaces, quote it:
WHERE `some Column1` = someValue1
You can even combine both:
WHERE someTable1.`some Column1` = someValue1
Why do you need to use aliases? The only reason to use aliases in your query would be for re-use in e.g. an "having" clause, like:
select count(*) as C
from some_table
where someAlias1=someValue1
and someAlias2=someValue2
having C > someLimit1;

How can I get just the column names for a given mysql query?

I am creating a utility which lets users enter a SQL query for the purposes of importing data to my database.
The first step is to show a list of resulting fields so the user can route them to the destination fields.
When users import from MSSQL, I can use SET FMTONLY ON to fetch the list of output columns that the query would produce if ran (assuming the query is valid in the first place).
I haven't been able to find a way to do this for MySQL. EXPLAIN doesn't list the resulting fields.
Given the following query:
SELECT CONCATENATE(first_name, " ", last_name) AS name, age, foo
FROM customers
ORDER BY name ASC;
I ultimately need to get a list of output fields only, like this:
{ "name", "age", "foo" }
How can I do this in MySQL?
SET FMTONLY ON still requires you to get the column names and types manually, it just generates an empty result set.
For MySQL, add a WHERE FALSE somewhere
SELECT CONCATENATE(first_name, " ", last_name) AS name, age, foo
FROM customers
WHERE FALSE
ORDER BY name ASC;
You get this lovely execution plan
"id";"select_type";"table";"type";"possible_keys";"key";"key_len";"ref";"rows";"Extra"
"1";"SIMPLE";NULL;NULL;NULL;NULL;NULL;NULL;NULL;"Impossible WHERE"
Then parse the columns as you would set fmtonly on with MSSQL
For complex queries (nested, group by, limit-ed), wrap it in a subquery
select * from (
<your wonderful brilliant complex query>
) x where false
MSSQL would have complained if the inner query contains ORDER BY without TOP, MySQL is ok with it.
I think you need to look at the resultsetmetada. I carries the number of columns, column name, and a few more about the result set.
I think you're looking for DESC {table_name}

I need some help getting MySql to output some results using a subquery

I'm storing a list of numbers inside a table as a varchar(255) and want to use this list in another query's "IN() clause.
Here's what I mean:
Table Data:
CREATE TABLE IF NOT EXISTS `session_data` (
`visible_portf_ids` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `session_data` (`visible_portf_ids`) VALUES
('45,44,658,659,661,45,44,658,659,661')
I want to run a query like this to return a list of portfolio's "QUERY #1":
SELECT portfolio_hierarchy_id, account_id, name, leaf_node_portf_id
FROM portfolio_hierarchy
WHERE account_id = 1
AND leaf_node_portf_id IN
(
(SELECT visible_portf_ids
FROM session_data
WHERE username = 'ronedog')
)
ORDER BY name ASC
The result of the query above returns only 1 row, when there are a total of 3 that should have been returned.
If I run the subquery alone like this:
(SELECT visible_portf_ids
FROM session_data
WHERE username = 'ronedog')
it will return a list like this:
45,44,658,659,661,45,44,658,659,661
But, when I run Query #1 above, only one row of data, which is associated with the "visible_portf_ids" of "45" is returned.
If I replace the subquery with hard coded values like this:
SELECT portfolio_hierarchy_id, account_id, name, leaf_node_portf_id
FROM portfolio_hierarchy
WHERE account_id = 1
AND leaf_node_portf_id IN (45,44,658,659,661,45,44,658,659,661)
ORDER BY name ASC
then I get all 3 rows I'm expecting.
I'm guessing that MySql is returning the list as a string because its stored as a varchar() and so it stops processing after the first "visible_portf_ids" is found, which is "45", but I'm not really sure.
Anyone got any ideas how I can fix this?
Thanks in advance.
You should think about restructuring your tables storing each value in a new row, instead of concatenating them.
Until then, you can use the FIND_IN_SET() function:
AND FIND_IN_SET(leaf_node_portf_id,
(SELECT visible_portf_ids
FROM session_data
WHERE username = 'ronedog'
LIMIT 1)
) > 0
Unfortunately MySQL does not have a function to split a delimited string. Your IN argument is a single string with the result of your subquery. The reason it works when you hard-code it is that MySQL is parsing the values.
I suggest that you redesign your data base to store the visible ports list as separate rows in a separate table. Then you can retrieve them and use them in subqueries like you tried.