LEFT JOIN CONCAT('hello_',c.id) possible? - php

IS it possible to have something like this:
SELECT c.id as id
FROM Channels c
LEFT JOIN CONCAT('hello_',c.id)
I NEED this concat with the c.id. THERE IS NO OTHER WAY.
So any tips?

You asked whether you can use an expression involving column values and functions like CONCAT to generate table names in queries in MySQL.
The short answer is no.
There's a longer answer involving MySQL prepared statements. That's basically a way to use string processing in a MySQL stored procedure to generate the text of a query to run.

If you intend to do it at SQL level: it is not possible. Table name tokens are not computed from expressions.
However, with php and creating a query dynamically, it should be quite trival to use a "modified" table name according to your need.
So, your concat() should be a php expression when building the query.
In the case where you are trying to join a (different) table based on the column value of a base table, you are far from any SQL semantics.
In that case you might want to rearrange your schema to merge all table instances identified by what your concat is now trying to compute info a single table and label each row with the logical table it belongs to.

Related

How it works a mysql query with alias?

I'm new in this comunnity and I need to work with a query that get data from a mysql database, I have this query, but I need to add a new table and I don't understand why the query has a alias, I don't know how it works, someone can help me?
This is my query:
SELECT ins.matricula, pe.nombres, pe.appaterno, pe.apmaterno, co.calleynum, co.colonia, co.municipio, co.telfijo, co.telcelular, pe.fechanac, pe.sexo, co.email, pe.institucion, tu.tnombres, tu.tappaterno, tu.tapmaterno, tu.direccion, tu.telefono, ins.fechains, ins.niveledu, ins.fechaini, ins.horario
FROM Inscripciones ins
LEFT JOIN Perfiles pe
ON pe.idperfil=ins.idperfil
LEFT JOIN Contactos co
ON co.idperfil = pe.idperfil
LEFT JOIN Tutores tu
ON tu.matricula = ins.matricula
WHERE pe.idperfil='$var'
I have read the mysql docs but I can't understand how it works.
In MySQL, an "alias" can be declared to simplify the query later.
Typically this is denoted with the "AS" operator, but can also be declared without "AS" - as in your example.
In your example:
SELECT ins.matricula, {...}
FROM Inscripciones ins {...}
The ins is set as an alias for the "Inscripciones" table.
This allows you to use ins throughout the query rather than typing out "Inscripciones." This can be seen in the SELECT statement.
Something to keep in mind - aliases in SQL can be declared after they're first used. This is the case in your example, where SELECT gets ins.matricula before you've actually declared ins as the alias for Inscripciones.
Sometimes this seems counter intuitive, but I promise it will make sense if you experiment with it a bit.
I find it less ambiguous to include the "AS" - which might help it make more sense as you're reading/writing the SQL query.
ex: ... FROM Inscripciones AS ins
To be clear, the use of the alias doesn't change the outcome of your query, but helps you write cleaner queries because you don't have to re-write the tablename every time you want to use it.
A SQL Alias is just what the name says, an alias. It's simply another name (a shorter name) for your table name.
So in your example the table name is Inscripciones, and in this line FROM Inscripciones ins you're saying "ins" is an alias to Inscripciones. Its just a way to make the query smaller/simpler. An alias is like a nickname (i.e. an alias for Michael is "Mike")
Aliases are normally set with "AS" like this:
SELECT * FROM Users AS u
but can be shortened like this:
SELECT * FROM Users u
Tables don't have to have aliases, unless you want to use the same table more than once, but it can make things shorter to type if the tables have columns named the same.
Instead of having to write
SELECT myfulltable1name.id, myfulltable2name.id
You can write
SELECT t1.id, t2.id
(If you've aliased your tables as t1 and t2)
Here's an example query where we use the same table more than once and need an alias to separate them:
SELECT
workAddresses.City as WorkCity,
homeAddresses.City as HomeCity
FROM
Addresses workAddresses
INNER JOIN
Addresses homeAddresses
ON
workAddresses.UserID = homeAddresses.UserID
WHERE
workAddresses.type = 'work' AND
homeAddresses.type = 'home'
Here the Addresses table stores work and home addresses for our users, with a type column to differentiate them. We want a result where tThe work and home address is on the same row, so we have to join the addresses table in twice, we give them sensible aliases so we can tell which is which, and we use where clause to make sure our workAddress table alias only refers to those records with type 'work'
You'll notice I also put an alias on the column names selected, so you can know which is the work City and which is the home city
Sometimes you MUST use an alias, like if you make a subquery, then the result must be aliased in order to be usable:
SELECT
workAddresses.City as WorkCity,
homeAddresses.City as HomeCity
FROM
(SELECT * FROM Addresses WHERE type ='work') workAddresses
INNER JOIN
(SELECT * FROM Addresses WHERE type ='home') homeAddresses
ON
workAddresses.UserID = homeAddresses.UserID
Here we got information from the addresses tables by subquery, and the bracketed sql statements must have aliases
Aliases are always declared at the first point that the object being aliased is brought into the query. For tables, this is in the FROM section, for columns this is in the SELECT section
It might help you to consider it as if the database actually does the from section first, connecting all the tables together, then it does the where, to filter the rows, finally it does the select, to pull just the columns you want. C# has a built in query language called LINQ, that presents things in this more logical way, FROM table WHERE something = something SELECT somecolumns - makes it easier to say "things are aliased when they are first introduced, like variable naming". SQL is what it is, has been for years. You get used to it
Alias in MySQL query is like a temporary short name for your table. They are not necessarily to be used but save your time when you need to create a complex queries. They are mainly used in queries when you use try to fetch data more than 1 table in single query using JOINS.
Suppose you have a table name 'employee_records'. Then trying to fetch the fields for table would look employee_records.id and so on. If you use alias for table name say 'e', then selecting fields will become e.id.
Hope that will make your point clear.
For more information in simple words read about SQL aliases over here - https://www.w3schools.com/sql/sql_alias.asp

PHP & MySQL web app - Selecting a single field (vs) select * from table

I am working on converting a prototype web application into something that can be deployed. There are some locations where the prototype has queries that select all the fields from a table although only one field is needed or the query is just being used for checking the existence of the record. Most of the cases are single row queries.
I'm considering changing these queries to queries that only get what is really relevant, i.e.:
select * from users_table where <some condition>
vs
select name from users_table where <some condition>
I have a few questions:
Is this a worthy optimization in general?
In which kind of queries might this change be particularly good? For example, would this improve queries where joins are involved?
Besides the SQL impact, would this change be good at the PHP level? For example, the returned array will be smaller (a single column vs multiple columns with data).
Thanks for your comments.
If I were to answer all of your three questions in a single word, I would definitely say YES.
You probably wanted more than just "Yes"...
SELECT * is "bad practice": If you read the results into a PHP non-associative array; then add a column; now the array subscripts are possibly changed.
If the WHERE is complex enough, or you have GROUP BY or ORDER BY, and the optimizer decides to build a tmp table, then * may lead to several inefficiencies: having to use MyISAM instead of MEMORY; the tmp table will be bulkier; etc.
EXISTS SELECT * FROM ... comes back with 0 or 1 -- even simpler.
You may be able to combine EXISTS (or a suitable equivalent JOIN) to other queries, thereby avoiding an extra roundtrip to the server.

Can I "cache" an embedded MySQL select used several times?

Working in Drupal 6, PHP 5.3, and MySQL, I'm building a query that looks roughly like this:
SELECT val from table [and some other tables joined in below]
where [a bunch of clauses, including getting all the tables joined up]
and ('foo' not in (select ...))
and (('bar' in (select...) and x = y)
or ('baz' in (select ...) and p = q))
That's not a great representation of what I'm trying to do, but hopefully it will be enough. The point is that, in the middle of the query there is an embedded SELECT that is used a number of times. It's always the same. It's not completely self-contained -- it relies on a value pulled from one of the tables at the top level of the query.
I'm feeling a little guilty/unclean for just repeating the query every time it's needed, but I don't see any other way to compute the value once and reuse it as needed. Since it refers to the value from a top level table, I can't compute it once outside the query and just insert the value into the query, either through a MySQL variable or by monkeying around with the query string. Or, so I think, anyway.
Is there anything I can do about this? Or, maybe it's a non-issue from a performance perspective: the code might be nasty, but parhaps MySQL is smart enough to cache the value itself and avoid executing the query over and over again? Any advice? Thanks!
You should be able to alias the result by doing SELECT ... AS alias, and then using in alias in the other queries, since the SELECT is really just a table.

Is there a way to make a table name dynamic in a query?

I am trying to create a Class-Inheritance design for products.
There is the base table that contains all the common fields. Then for each product type there is a separate table containing the fields that are for that product type only
So in order to get all the data for a product I need to JOIN the base table with whatever table that correlates to the product_type listed in the base table. Is there a way to make this query join on the table dynamically?
Here is a query to try to illustrate what I am trying to do:
SELECT * FROM product_base b
INNER JOIN <value of b.product_type> t
ON b.product_base_id = t.product_base_id
WHERE b.product_base_id = :base_id
Is there a way to do this?
No, there's no way to do this. The table name must be known at the time of parsing the query, so the parser can tell if the table exists, and that it contains the columns you reference. Also the optimizer needs to know the table and its indexes, so it can come up with a plan of what indexes to use.
What you're asking for is for the table to be determined during execution, based on data found row-by-row. There's no way for the RDBMS to know at parse-time that all the data values correspond to real tables.
There's no reason you would do this to implement Class Table Inheritance. CTI supports true references between tables.
You're instead describing the antipattern of Polymorphic Associations.
Make 2 queries:
First select < value of b.product_type > and then use it in the second one (the one that you have, but replace < value of b.product_type > with the result from the first one).
No. There would be little point even if it were possible, as the query optimiser would not be able to make a plan without knowing anything about the right- hand side of the join.
You need to construct the query using concatenation or similar, but make sure that you only use a valid table name to avoid injection attacks.
You can create a procedure that takes the table name as an argument and constructs a dynamic-SQL query. But it's probably easier to do this in your server-side code (PHP). But rather than make it a variable (and as suggested vulnerable to injection attacks), create separate classes for the different join combinations. Use another class (like a dispatcher) to determine the correct class to instantiate.

Whats better- query with long 'where in' condition or many small queries?

Maybe it's a little dumb, but i'm just not sure what is better.
If i have to check more than 10k rows in db for existanse, what i'd do?
#1 - one query
select id from table1 where name in (smth1,smth2...{till 30k})
#2 - many queries
select id from table1 where name=smth1
Though, perfomance is not the goal, i don't want to go down with mysql either ;)
Maybe, any other solutions will be more suitable...
Thanks.
upd: The task is to fetch domains list, save new (that are not in db yet) and delete those that dissappeared from list. Hope, it'll help a little...
What you should do is create a temp table, insert all of the names, and (using one query) join against this table for your select.
select id
from table1 t1
inner join temptable tt on t1.name = tt.name
The single query will most likely perform better as the second will give a lot of round-trip delays. But if you have a lot of names like in your example the first method might cause you to hit an internal limit.
In this case it might be better to store the list of names in a temporary table and join with it.
Depending on your future needs to do similar things, you might want to add a function in the database 'strlist_to_table'. Let the function take a text where your input is delimited by a delimiter character (possibly also passed to function), split it on the delimiter to create a on-the-fly table. Then you can use
where in strlist_to_table('smth1|smth2', '|')
and also get protection from sql injection (maybe little Bobby Tables appears in the input).
Just my 2 cents...
I'm not sure how flexible your application design is, but it might be worth looking into removing the delimited list altogether and simply making a permanent third table to represent the many-to-many relationship, then joining the tables on each query.

Categories