MySQL "exists" function in "where" clause - mysql

I would like to select a field only if the field exists on the table. If it does not exist, then I want to select a different field in the "where" clause.
The use case for this is that I have several similar tables, some of which have a "user_id" field and others do not, but rather than hard-coding all the tables that have this, I want to just check for the existence of the field, so that I can use the same sql for all. Those that do not have user_id use the "id" field instead for my application.
This code gives me the error
Unknown column 'user_id' in 'where clause'
for the table that does not have a user_id field.
I am using MySQL 5.7
select id from users
where
if (
exists( select 1 from information_schema.columns where table_name = 'users' and column_name = 'user_id' ),
user_id > 10,
id > 10);

I don't think you can achieve what you're looking to do in the way you're looking to do it.
The interpreter has no expectation that you might only want to use one of these fields, and it correctly points out that one of them is not valid for that query.
I think you'd have a far easier time having a common field name for everything you're searching on.
Consider creating views that provide all the columns of the base table and map the varying column as user_id.
e.g.
CREATE VIEW uniform_user
AS
SELECT
id,
id as user_id,
...
You can then exploit these views rather than the base tables and know that a user_id will definitely exist in each.
SELECT user_id FROM uniform_user
etc.

Related

use column names from inner query select the columns to display in outer query

My scenario is as follows( in MySQL)
I have a table say table 1, which has 2 columns:
userID, column_acess
Table 2 which has a list of columns say col1,col2,col3, etc.
Now What I would like to do is use pymySQL to query table 1 for the columns a particular userID is allowed to acesss, by inspecting the column, acess field ( which will contain a comma seperated list of columns in tabl2), and use that result in another sql query ( which works on table2) to actually get the data from the respective columns a user is allowed to acess.
So essentially I would like something like:
Select (Select column_acess from tabl1 where user_ID='123') from table2
So inner query should return the list of columns say col1, col2, which would be used to select the columns in the outer query in table2
How do I do that in mySQL?
I strongly encourage you too read this post. You should either first store columns in variable or use dynamic sql query. Use SELECT result as COLUMN name in other SELECT
BTW your schema is not even in 1 NF since you don’t have atomic values in table 1. You should avoid that.
MySQL supports the granting of column-level privileges to users, using the standard grant statement.
I would suggest that you start with the documentation on this subject.
An alternative to using grant for columns is to create views for different user types. This is, in fact, the more general solution, because the views can filter rows as well as columns. The idea is that the underlying tables are not directly accessible. The views are, so all access needs to go through the views.

Group by statement column name resolution

I have a query like this (more columns in reality)
select
custom_amend_column_function(colname) as colname
from source_table
group by colname
I've used this construct a lot.It appears to have always used the output from the function rather than the input to group data by.
Now for the first time today I have run this statement directly into a new table like this:
create table new_table as
select
custom_amend_column_function(colname) as colname
from source_table
group by colname
Curiously by adding the first line, I am getting an error message that my query is using an ambiguous column name in the group statement.
As group by can use new column names (ie. the below works) I always expected that group by will first use the columns defined in the select statement and then look at the underlying table(s) if it cannot find the names.
select
custom_amend_column_function(colname) as new_colname
from source_table
group by new_colname
Am I right? Is the error message right? I cannot find any place this is documented either for the SQL standard or for MySQL.
I know I could avoid this by just creating a new column name, but I want to figure this out as I may need to review existing queries if it is indeed ambiguous.
To trace the problem do an
EXPLAIN EXTENDED SELECT ...
On your query. Beside the normal output this will give you a warning containing the query as it is seen by the optimizer. All implicit renaming is done here, so you can see why the column name is ambiguous.
I think you can solve this by saying
... GROUP BY 1
instead of providing the column name in the group by.

Correct database operation to get the data desired

Ok, so I've got a MySQL database with several tables. One of the tables (table A) has the items of most interest to me.
It has a column called type and a column called entity_id. The primary key is something called registration_id, which is more or less irrelevant to me currently.
Ultimately, I want to gather all items of a particular type, but which have a unique entity_id. The only problem with this is that entity_id in table A is NOT a unique key. It is possible to have multiple registration_ids per entity_id.
Now, there's another table (table B) which has only a list of unique entity_ids (that is, it is the primary key on that table), however there's no information on the type in that table.
So with these two tables, what is the best way to get the data I want?
I was thinking some sort of way (DISTINCT) that I could use on the first table, alone, or possibly a join of some sort (I'm still relatively new to the concept of joins) between table A and table B, combining the entity_id from table B with the type from table A.
What's the most efficient database operation for this for now? And should I (eventually, not right now as I simply do not have the time, sadly) change the database structure for greater efficiency?
If anyone needs any additional information or graphics, let me know.
If I understand correctly you can use either GROUP BY
SELECT entity_id
FROM table1
WHERE type = ?
GROUP BY entity_id
or DISTINCT
SELECT DISTINCT entity_id
FROM table1
WHERE type = ?
Here is SQLFiddle demo
Table Joins are a costly operation. If you are dealing with large datasets then the time it takes to execute a join operation is non-negligible.
The following SQL statement will grab all entity_id's and group them by type. So for each entity_id only 1 of each type will be in the result set:
SELECT type, entity_id FROM TableA GROUP BY type, entity_id;
I think this is what you are looking for. Try this to give you the types that have only one (unique) entity_id.
SELECT type , count(entity_id)
FROM table1
GROUP BY type
HAVING COUNT(entity_id)=1
Here is the SQL Fiddle

Subquery for fetching table name

I have a query like this :
SELECT * FROM (SELECT linktable FROM adm_linkedfields WHERE name = 'company') as cbo WHERE group='BEST'
Basically, the table name for the main query is fetched through the subquery.
I get an error that #1054 - Unknown column 'group' in 'where clause'
When I investigate (removing the where clause), I find that the query only returns the subquery result at all times.
Subquery table adm_linkedfields has structure id | name | linktable
Currently am using MySQL with PDO but the query should be compatible with major DBs (viz. Oracle, MSSQL, PgSQL and MySQL)
Update:
The subquery should return the name of the table for the main query. In this case it will return tbl_company
The table tbl_company for the main query has this structure :
id | name | group
Thanks in advance.
Dynamic SQL doesn't work like that, what you created is an inline-view, read up on that. What's more, you can't create a dynamic sql query that will work on every db. If you have a limited number of linktables you could try using left-joins or unions to select from all tables but if you don't have a good reason you don't want that.
Just select the tablename in one query and then make another one to access the right table (by creating the query string in php).
Here is an issue:
SELECT * FROM (SELECT linktable FROM adm_linkedfields WHERE name = 'company') as cbo
WHERE group='BEST';
You are selecting from DT which contains only one column "linktable", then you cant put any other column in where clause of outer block. Think in terms of blocks the outer select is refering a DT which contains only one column.
Your problem is similar when you try to do:
create table t1(x1 int);
select * from t1 where z1 = 7; //error
Your query is:
SELECT *
FROM (SELECT linktable
FROM adm_linkedfields
WHERE name = 'company'
) cbo
WHERE group='BEST'
First, if you are interested in cross-database compatibility, do not name columns or tables after SQL reserved words. group is a really, really bad name for a column.
Second, the from clause is returning a table containing a list of names (of tables, but that is irrelevant). There is no column called group, so that is the problem you are having.
What can you do to fix this? A naive solution would be to run the subquery, run it, and use the resulting table name in a dynamic statement to execute the query you want.
The fundamental problem is your data structure. Having multiple tables with the same structure is generally a sign of a bad design. You basically have two choices.
One. If you have control over the database structure, put all the data in a single table, linktable for instance. This would have the information for all companies, and a column for group (or whatever you rename it). This solution is compatible across all databases. If you have lots and lots of data in the tables (think tens of millions of rows), then you might think about partitioning the data for performance reasons.
Two. If you don't have control over the data, create a view that concatenates all the tables together. Something like:
create view vw_linktable as
select 'table1' as which, t.* from table1 t union all
select 'table2', t.* from table2 t
This is also compatible across all databases.

How to count the columns of a MySQL query when the number of columns returned is dynamic?

Is it possible to retrieve the count of the number of columns a query returns? This can be easily done with a bound scripting language such as php, but I'm looking for db only solution.
Example:
CountCols(SELECT 'a','b','c')
=> 3
CountCols(SELECT * FROM information_schema.session_variables)
=> 2
Would this work for you?
select
count(*)
from
`information_schema`.`columns`
where
`table_schema` = 'my_table_schema' and `table_name` = 'my_table_name';
You only need to use table_schema if the table name exists in more than one database.
Based on your response comment, you are looking to count a dynamic number of columns. You may be able to do this with a temporary table, but you cannot access the data of a temporary table without possibly installing a patch.
Of note, there is a similar outstanding SO question asking how to select columns from a temporary table.
Well if you want to know the columns in a table just do:
DESCRIBE `table_name`
Otherwise there is no "real" way to get the number of columns in a select query since other than selecting * you select certain columns --> so you will know how many columns you are selecting.
You'll find your answer here most likely: http://dev.mysql.com/doc/refman/5.0/en/columns-table.html
Write a query off of that that takes a table name param and then query for columns of that table and sum that up.