MySQL subquery quirk or expected behaviour? - mysql

I'm trying to gain more knowledge concerning the MySQL database and I'm hoping someone over here might be able to explain to me the following issue as I cant find much about this particular behavior anywhere:
This works:
SELECT justaname FROM (SELECT productName AS justaname FROM kclbs_products) sdfsdfsd
While this doesnt:
SELECT justaname FROM (SELECT productName AS justaname FROM kclbs_products)
This really puzzle's me and I believe it to be a quirk because whatever I turn the string 'sdfsdfsd' into doesn't matter, the query still works, even when its just a single character (or a very large sequence of characters for that matter). This 'issue' doesn't represent a problem to me currently but I would really like to know the 'why' behind it to be able to deal with this kinda behavior anywhere in the possible future should I ever have to.
Thanks in advance.
[UPDATE]
Two users have helped providing me with the answer to my question, so its solved, and thanks!

It subquery name
SELECT ... FROM (subquery) [AS] name ...
Here is reference from mysql docs
The [AS] name clause is mandatory, because every table in a FROM clause must have a name. Any columns in the subquery select list must have unique names.
For futher info use https://dev.mysql.com/doc/refman/5.7/en/from-clause-subqueries.html

This is not related to MySQL, and its a rule in all DBMS's. if you use subquery in FROM clause you must alias it.
When you write something after subquery (like sdfsdfsd), DBMS consider it as alias name of table derived from subquery.
You can see some information about subqueries in FROM clause in:
https://dev.mysql.com/doc/refman/5.7/en/from-clause-subqueries.html
and
http://www.geeksengine.com/database/subquery/subquery-in-from-clause.php
it also explained in subquery in FROM must have an alias

Related

Mysql not working when used double alias

Hey guys am really new to mysql.I have heard of alias in mysql and i have tried double alias with the string like
select ('name' as bae,'age' as ages) as person;
When i run the above code it doesnt give me the output and raises the error.I dont understand why the double alias didnt works in mysql.
Any help to make this one correct would be really appreciated..Thanx in advance
The problem with your query are the parentheses. They represent a single expression and you don't put aliases (or commas usually) inside expressions. So, this fixes the immediate problem:
select 'name' as bae, 'age' as ages
I'm not sure what the second "as person" is supposed to be. Perhaps you want a subquery:
select person.*
from (select 'name' as bae, 'age' as ages) person
A really basic MySQL query should look something like:
SELECT
[COLUMN_NAME] AS [ALIAS_NAME]
FROM
[TABLE_NAME]
Based on your query it appears you are trying to retrieve the two columnns name and age from the person table.
If this is the case, the following query can help you:
SELECT
name AS bae,
age AS ages
FROM
person
But, this is still just one big guess, if you really want us to help you with your problems, you should give some more information about what you are trying to achieve.

Fulltext search that isn't exact match

I have a MySQL-table called "customers1" running engine MyISAM. I've created a full text index on the columns name,adress and zip. Now one of the customers in that table is me. I spell my name "Gildebrand". Now i can't expect that the users can spell my name correctly, many might write "Glidebrant", but still want to find my. How could i do that search in SQL?
If i run the following query right now
SELECT * FROM customers1 WHERE MATCH(name,adress,zip) AGAINST('Gildebrand')
It finds me, of course. But if i misspell, "Glidebrand", it doesn't find me. What would be the best approach to this?
I would say the closest you can get from such a result if by using SOUNDEX() http://www.w3resource.com/mysql/string-functions/mysql-soundex-function.php
I have a generic search similar to yours. Here's basically what I do:
SELECT * FROM customers1 WHERE MATCH(name,adress,zip) AGAINST('?')
UNION
SELECT * FROM customers1 WHERE name LIKE ('?%')
This allows the user to just enter a prefix also.
If the user realizes they can't spell your name, but they're sure it starts with Gil, then they can just type that.
You can add additional UNION clauses if you want to support prefixes on other columns too.

Do i really need to include table names or AS in JOINS if columns are different?

I noticed te other day I can joins in mysql just as easily by doing,
SELECT peeps, persons, friends FROM tablea JOIN tableb USING (id) WHERE id = ?
In stead of using,
SELECT a.peeps, a.persons, b.friends FROM tablea a JOIN tableb b USING (id) WHERE id = ?
It only works if there is no matching column names, why should I do the second rather than the first?
No, you don't need to, but in my humble opinion you really should. It's almost always better in my experience to be explicit with what you're trying to do.
Consider the feelings of the poor guy (or girl) who has to come behind you and try to figure out what you were trying to accomplish and in which tables each column resides. Explicitly stating the source of the column allows one to look at the query and glean that information without deep knowledge of the schema.
Query 1 will work (as long as there are no ambiguous column names).
Query 2 will
be clearer
be more maintainable (think of someone who doesn't know the database schema by heart)
survive the addition of an ambiguous column name to one of the tables
So, don't be lazy because of that pitiful few saved keystrokes.
It's not necessary if you have no duplicate column names. If you do, the query will fail.

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

MS-Access design pattern for last value for a grouping

It's common to have a table where for example the the fields are account, value, and time. What's the best design pattern for retrieving the last value for each account? Unfortunately the last keyword in a grouping gives you the last physical record in the database, not the last record by any sorting. Which means IMHO it should never be used. The two clumsy approaches I use are either a subquery approach or a secondary query to determine the last record, and then joining to the table to find the value. Isn't there a more elegant approach?
could you not do:
select account,last(value),max(time)
from table
group by account
I tested this (granted for a very small, almost trivial record set) and it produced proper results.
Edit:
that also doesn't work after some more testing. I did a fair bit of access programming in a past life and feel like there is a way to do what your asking in 1 query, but im drawing a blank at the moment. sorry.
After literally years of searching I finally found the answer at the link below #3. The sub-queries above will work, but are very slow -- debilitatingly slow for my purposes.
The more popular answer is a tri-level query: 1st level finds the max, 2nd level gets the field values based on the 1st query. The result is then joined in as a table to the main query. Fast but complicated and time-consuming to code/maintain.
This link works, still runs pretty fast and is a lot less work to code/maintain. Thanks to the authors of this site.
http://access.mvps.org/access/queries/qry0020.htm
The subquery option sounds best to me, something like the following psuedo-sql. It may be possible/necessary to optimize it via a join, that will depend on the capabilities of the SQL engine.
select *
from table
where account+time in (select account+max(time)
from table
group by account
order by time)
This is a good trick for returning the last record in a table:
SELECT TOP 1 * FROM TableName ORDER BY Time DESC
Check out this site for more info.
#Tom
It might be easier for me in general to do the "In" query that you've suggested. Generally I do something like
select T1.account, T1.value
from table T as T1
where T1 = (select max(T2.time) from table T as T2 where T1.account = T2.Account)
#shs
yes, that select last(value) SHOULD work, but it doesn't... My understanding although I can't produce an authorative source is that the last(value) gives the last physical record in the access file, which means it could be the first one timewise but the last one physically. So I don't think you should use last(value) for anything other than a really bad random row.
I'm trying to find the latest date in a group using the Access 2003 query builder, and ran into the same problem trying to use LAST for a date field. But it looks like using MAX finds the lates date.
Perhaps the following SQL is clumsy, but it seems to work correctly in Access.
SELECT
a.account,
a.time,
a.value
FROM
tablename AS a INNER JOIN [
SELECT
account,
Max(time) AS MaxOftime
FROM
tablename
GROUP BY
account
]. AS b
ON
(a.time = b.MaxOftime)
AND (a.account = b.account)
;