In SQL, how do I exclude result from SELECT * FROM ...? - mysql

I know my title is not very descriptive... let me explain in details here.
Let say, if a table has 26 fields. e.g. field_a ... field_z. and I only want a select query to return me 15 fields only.
So, normally, I will do SELECT field_a, field_b ... field_o FROM myTable.
Which is tedious. Is there a way in MYSQL that I can do a SELECT * and tell it not to return certain fields?
e.g. soemthing like SELECT * exclude (field_p, field_q .. field_z) FROM myTable?
Thanks all for the answers. :)

SELECT * is evil.
You should never use it in production code.
You should always specify the columns you want returned, like so:
SELECT `column1`, `column2`, `someothercolumn`
FROM `myTable`
As always, the documentation can help with the nitty gritty!

SQL itself does not support the functionality you are asking for. (If it did, it would have the same problems as select *. See other's comments)
This is what I do when I'm using MySQL:
Fire up mysql command line client
Perform a describe my_table
Copy the data in Field column (mouse select)
Paste data in my editor (TextPad)
Manually remove the columns I don't need
Run a macro that substitutes new line for a comma (and insert a table alias)
All in all, it takes around 20-30 seconds to create a select list regardless of the number of columns. This way ensures that I don't misspell or forget any columns.

delimiter //
DROP PROCEDURE IF EXISTS `getColumnNames`//
CREATE PROCEDURE `getColumnNames` (db_name CHAR(255), t_name CHAR(255), ex_name CHAR(255))
BEGIN
SELECT group_concat(column_name) FROM `information_schema`.`COLUMNS` C
WHERE
table_schema = db_name
AND
table_name = t_name
AND
column_name not in (ex_name)
GROUP BY table_schema,table_name;
END
//
delimiter ;
call getColumnNames("Db_name", "tbl_name", "col_to_exclude");

No use the fields you want (select * shouold not appear in production code even if you want allthe fields). I don't know about mySQL but in SQL Server I can drag and drop the columns which makes it easy to specify, is there a way to make this less tedious by dragging and dropping?

There's no way to do this because 'SELECT *' is a bad idea in a production environment anyhow. Just think of all the extra error-catching that would need to be done if something like this existed -- what if the excluded field didn't exist in the table? Does this create an error? A warning?
Enumerating all your fields is indeed tedious, but it's the correct way to do it. It makes your code (a little bit more) self-documenting, and helps stop errors early in the cycle. For one example, if 'user_name' is eventually renamed to 'username' for whatever reason, the SQL statement will fail and you won't have a strange data lolling around in your code waiting to be traced down.

I hope that there's none way to do this. Even if there is one, I'd suggest not to use it.
Kindof solution is to create a view that excludes the one row you want to have excluded, and you can select * from the view.

Related

Set then Select

Can somebody please help me with this simple (but I don't know how) task?
In order to avoid wasting time fixing every single line, I'm trying to do something like this
SET #auditor = a, b, c;
SELECT *
FROM Audits
WHERE auditor in (#auditor)
My query indeed is really long and this part "WHERE auditor in (#auditor)" will be repetitive. Therefore, doing some kind of Set first will make it faster to update when there are some changes in the work force (we hire "d" and/or "b" left)
Thanks in advance
I recommend using a temporary table at the top of your query instead:
CREATE TEMPORARY TABLE FilteredAudits AS (SELECT * FROM Audits WHERE Auditor IN (a,b,c))
Then replace Audits with FilteredAudits as needed.
The benefits to this approach is that you guarantee the filter will only be applied once, meaning the rest of the query will JOIN to the smallest data set possible, and you don't have to repeat your IN() filter throughout the query.
You can use an array variable and FIND_IN_SET
SET #auditors = 'a,b,c';
SELECT *
FROM Audits
WHERE FIND_IN_SET(auditor,#auditors)
Explanation:
FIND_IN_SET(auditor,#auditors) is true is auditor is found in #auditors and in this case it returns the index.
But I would consider saving the auditors in a separate table rather than in a variable to better keep track of them.
you cannot set a parameter like an array. you will have to do something like
set #auditor='a,b,c'
now if auditor is a number this should work but if it is anything other then you will have to create a funciton dbo.[tfn_SplitList] on your system you will use it like below
auditor in(select List from dbo.[tfn_SplitList](#auditor ,','))

SQL: Extract column headings from Dynamically Generated Table

After selecting data from multiple tables, like this:
SELECT games.name, scores.score
FROM games, scores
WHERE players.id = scores.player_id
..can I extract the column headings of this newly generated table?
The statement I'd normally use would be as follows:
SELECT column_name
FROM information_schema.columns
WHERE table_name=table
But naturally this would not work for a dynamically generated table with no name
Help much appreciated!
Edit: I'm using the MariaDB client
..can I extract the column headings of this newly generated table?
No. Mostly because you've not created a table. Just a result set. I think you already know this, because you've already looked at the information schema :)
Unfortunately it seems even creating a temporary table won't help - because those aren't stored in the information schema either. I don't think you can declare cursors for SHOW COLUMN... statements either.
I don't think you've got a way to do it I'm afraid.
If it's a prepared statement (with the select statement held in a variable) you could probably chop it up using some ugly string manipulation...?
It might at this point be worth asking "more abstractly, what problem are you trying to solve?"

SQL newbie: execution order of subqueries?

Warning: This is a soft question, where you'll be answering to someone who has just started teaching himself SQL from the ground up. I haven't gotten my database software set up yet, so I can't provide tables to run queries against. Some patience required.
Warnings aside, I'm experimenting with basic SQL but I'm having a little bit of a rough time getting a clear answer about the inner workings of subqueries and their execution order within my query.
Let us say my query looks something like shit:
SELECT * FROM someTable
WHERE someFirstValue = someSecondValue
AND EXISTS (
SELECT * FROM someOtherTable
WHERE someTable.someFirstValue = someOtherTable.someThirdValue
)
;
The reason I'm here, is because I don't think I understand fully what is going on in this query.
Now I don't want to seem lazy, so I'm not going to ask you guys to "tell me what's going on here", so instead, I'll provide my own theory first:
The first row in someTable is checked so see if someFirstValue is the same as someSecondValue in that row.
If it isn't, it goes onto the second row and checks it too. It continues like this until a row passes this little inspection.
If a row does pass, it opens up a new query. If the table produced by this query contains even a single row, it returns TRUE, but if it's empty it returns FALSE.
My theory ends here, and my confusion begins.
Will this inner query now compare only the rows that passed the first WHERE? Or will it check all the items someTable and someOtherTable?
Rephrased; will only the rows that passed the first WHERE be compared in the someTable.someFirstValue = someOtherTable.someThirdValue subquery?
Or will the subquery compare all the elements from someTable to all the elements in someOtherTable regardless of which passed the first WHERE and which didn't?
UPDATE: Assume I'm using MySQL 5.5.32. If that matters.
The answer is that SQL is a descriptive language that describes the result set being produced from a query. It does not specify how the query is going to be run.
In your case the query has several options on how it might run, depending on the database engine, what the tables look like, and indexes. The query itself:
SELECT t.*
FROM someTable t
WHERE t.someFirstValue = t.someSecondValue AND
EXISTS (SELECT *
FROM someOtherTable t2
WHERE t.someFirstValue = t2.someThirdValue
);
Says: "Get me all columns from SomeTable where someFirstValue = someSecondValue and there is a corresponding row in someOtherTable where that's table column someThirdValue is the same as someFirstValue".
One possible way to approach this query would be to scan someTable and first check for the first condition. When the two columns match, then look up someFirstValue in an index on someOtherTable(someThirdValue) and keep the row if the values match. As I say, this is one approach, and there are others.

MySQL Function to return table name to be used in a query

Can I use a MySQL function or procedure to return table names that can be used in a query?
Something like
SELECT * FROM get_db_table_name(2342352412);
where get_db_table_name() is a user defined function which accepts a user_id as a parameter and returns the db.table where that user resides. I have not been able to do this this way because MySQL complains about the syntax (my guess is it's because I had to define a return type for the function, which I tried as VARCHAR(30) and it is wrong or impossible). So, is this possible?
The story is that I have a few databases that are essentially shards. Let's call them user_1, user_2, etc.
I also have a single table, say emails that contains records with user_ids from tables user_1.users, user_2.users, etc.
Since I know a way to compute which table an id is from just by looking at the id, I just want a function that would accept an input and return a db.table name to be used.
Thank you!
P.S. I'd like to use the above SELECT query as a VIEW definition that would bring the user's name from the proper db/table by doing a JOIN across the proper table.
You can use prepared statements for this, e.g.:
....
SET #tbl = 'nameofmytable';
SET #sql = CONCAT( 'SELECT * FROM ', #tbl );
EXECUTE #sql;
...
When defining a view you must specify the tables. You can not define a view on "SELECT FROM whereever needed" ...
The view definition is “frozen” at creation time, so changes to the underlying tables afterward do not affect the view definition. For example, if a view is defined as SELECT * on a table, new columns added to the table later do not become part of the view.
You must specify my view is on this, this and this table. Looking at this you can not do SELECT * FROM func(id) because you can not specify what the results of this function will be (depending on the input parameter).
The syntax of SELECT is
SELECT * FROM table_references
The only way of "dynamic" SELECT is with dynamic SQL, what #Zed answered...
I'm sorry if my answer is incomplete, but I don't know your problem in details. Good Luck!
Parameterising the table name is considered to be usually because of bad database design. Is it really not possible to have all the entities of the same type (in this case, your users) in one table?

Mysql "magic" catch all column for select statement

Is there a way that I can do a select as such
select * from attributes where product_id = 500
would return
id name description
1 wheel round and black
2 horn makes loud noise
3 window solid object you can see through
and the query
select * from attributes where product_id = 234
would return the same results as would any query to this table.
Now obviously I could just remove the where clause and go about my day. But this involves editing code that I don't really want to modify so i'm trying to fix this at the database level.
So is there a "magical" way to ignore what is in the where clause and return whatever I want using a view or something ?
Even if it was possible, I doubt it would work. Both of those WHERE clauses expect one thing to be returned, therefore the code would probably just use the first row returned, not all of them.
It would also give the database a behaviour that would make future developers pull their hair out trying to understand.
Do it properly and fix the code.
or you could pass "product_id" instead of an integer, if there's no code checking for that...so the query would become:
select * from attributes where product_id = product_id;
this would give you every row in the table.
If you can't edit the query, maybe you can append to it? You could stick
OR 1=1
on the end.
You may be able to use result set metadata to get what you want, but a result set won't have descriptions of fields. The specific API to get result set metadata from a prepared query varies by programming language, and you haven't said what language you're using.
You can query the INFORMATION_SCHEMA for the products table.
SELECT ordinal_position, column_name, column_comment
FROM INFORMATION_SCHEMA.columns
WHERE table_name = 'products' AND schema_name = 'mydatabase';
You can restructure the database into an Entity-Attribute-Value design, but that's a much more ambitious change than fixing your code.
Or you can abandon SQL databases altogether, and use a semantic data store like RDF, which allows you to query metadata of an entity in the same way you query data.
As far out as this idea seems I'm always interested in crazy ways to do things.
I think the best solution I could come up with is to use a view that uses the products table to get all the products then the attributes table to get the attributes, so every possible product is accounted for and all will get the same result