Using an ALIAS in an INNER JOIN query? - mysql

I think the title explain very well my issue, I looked at a lot of subject in forum and else about this but I am still stuck. I don't really understand how to do it, and maybe someone here will be able to make me understand. (I hope)
My query is here:
SELECT Name, A, B, C, D, E, F
FROM Data
INNER JOIN User_Access ON Data.Name = User_Access.Name
WHERE User_Access.Channel = 'TEST'
I know that I have to use an alias for "Name" but I can not do it.
For now, I think my best almost-answer to my issue is this :
SELECT Name AS N, A, B, C, D, E, F
FROM Data
INNER JOIN User_Access ON Data.N = User_Access.Name
WHERE User_Access.Channel = 'TEST'
But it's not working and I have an invalid name error.
Thank's in advance for your help !

SELECT User_Access.Name, A, B, C, D, E, F
FROM Data
INNER JOIN User_Access ON Data.N = User_Access.Name
WHERE User_Access.Channel = 'TEST'
I have replaced the Name (as is key word) with User_Access.Name (changing the column name that is appending with the actual table's name).

Where a column name is common between n tables you need to qualify it so that sql knows which one you mean.This will work
SELECT data.Name, A, B, C, D, E, F
FROM Data
INNER JOIN User_Access ON Data.Name = User_Access.Name
WHERE User_Access.Channel = 'TEST'
as will
SELECT d.Name, A, B, C, D, E, F
FROM Data d
INNER JOIN User_Access ON d.Name = User_Access.Name
WHERE User_Access.Channel = 'TEST'

From Logical Processing Order of the SELECT statement:
The following steps show the logical processing order, or binding
order, for a SELECT statement. This order determines when the objects
defined in one step are made available to the clauses in subsequent
steps. For example, if the query processor can bind to (access) the
tables or views defined in the FROM clause, these objects and their
columns are made available to all subsequent steps. Conversely,
because the SELECT clause is step 8, any column aliases or derived
columns defined in that clause cannot be referenced by preceding
clauses. However, they can be referenced by subsequent clauses such as
the ORDER BY clause. The actual physical execution of the statement is
determined by the query processor and the order may vary from this
list.
FROM
ON
JOIN
WHERE
GROUP BY
WITH CUBE or WITH ROLLUP
HAVING
SELECT
DISTINCT
ORDER BY
TOP
Notice that the SELECT is in position 8, where as JOIN and ON are in positions 3 and 2 respectively. Therefore you cannot reference a column by it's alias defined in the SELECT in the ON; as the SELECT hasn't been processed yet. Effectively, the only place you can reference a column by it's alias (in the same scope) is in the ORDER BY.
If you really wanted to to this, you could use as CROSS APPLY and VALUES operator, but (honestly) you wanting to type N instead of Name in the ON is more laziness:
SELECT V.N, D.A, D.B, D.C, D.D, D.E, D.F --I assume there are all from the Data table
FROM Data D
CROSS APPLY (VALUES(D.[Name])) V(N)
INNER JOIN User_Access UA ON V.N = UA.Name
WHERE UA.Channel = 'TEST';

Name is a reserved word, you need to enclose that in square bracket
SELECT [Name], A, B, C, D, E, F
FROM Data
INNER JOIN User_Access ON Data.N = User_Access.Name
WHERE User_Access.Channel = 'TEST'

Related

Check condition across several rows from a join

I have some entities A which can all have one or more B. How can I query "all entities A which have this and that from B"?
I can query "all entities A which have "this" or "that" from B":
SELECT *
FROM A
INNER JOIN B ON B.A_id = A.id
WHERE f = "this" OR f = "that"
GROUP BY A.ID
But I can’t check that they have "this" and "that", because I can’t check something across different rows from A.
I might use a GROUP_CONCAT, but then how can I effectively check that "blah,thing,foo,bar" has blah and foo without some unmaintainable REGEXP mess?
(I actually love regexes, but not so much in the context of an SQL query, for something that seems like it wouldn’t need a regex).
SELECT *, GROUP_CONCAT(f)
FROM A
INNER JOIN B ON B.A_ID = A.ID
WHERE f = "this" OR f = "that"
GROUP BY A.ID
How can I query "all entities A which have this and that from B"?
For such tasks we usually don't join, but use EXISTS or IN instead. E.g.
select *
from a
where id in (select a_id from b where f = 'this')
and id in (select a_id from b where f = 'that');
Here is a solution with an aggregation. In this particular case I see no advantage in using this. There are other situations, though, when an aggregation may be the appropriate solution.
select *
from a
where id in
(
select a_id
from b
group by a_id
having max(f = 'this') = 1
and max(f = 'that') = 1
);
In MySQL true is 1 and false is 0, so taking the maximum of a boolean expression tells us, whether there is at least one row for which the condition is true.
Your own query works, too, by the way, if you add the appropriate HAVING clause. And there is no regular expression matching needed for that. As your WHEREclause limits f to 'this' and 'that', your GROUP_CONCAT result can never be 'this,something_else;that', but only contain 'this' and 'that'. Well, depending on the table there may be duplicates, like 'this,this,that'. Use an ORDER BY clause and DISTINCT:
SELECT a.*
FROM a
INNER JOIN b ON b.a_id = a.id
WHERE b.f IN ('this', 'that')
GROUP BY a.id
HAVING GROUP_CONCAT(DISTINCT b.f ORDER BY b.f) = 'that,this';

How to return some predefined value when no row returned from big query with multiple column is selected

My query has multiple column being selected but now i want when no returned I want some dummy value to be returned.
For example in the following query:
SELECT a.abc, b.def, c.ghi
FROM comp a, damp b, champ c, omp d
WHERE a.id=b.id
and b.id=c.id
and c.id= d.id
ORDER BY a.abc desc
if there is no row returned I wanted to display atleast one column with some value, can somebody suggest me how can I achieve this.
I have already gone through some suggestion but none worked. Any help would be appreciated.
In oracle you could do something like this:
WITH mybigselect AS
(
SELECT a.abc, b.def, c.ghi
FROM comp a
JOIN damp b ON a.id = b.id
JOIN champ c ON b.id = c.id
JOIN omp d ON c.id = d.id
ORDER BY a.abc desc
)
SELECT * FROM mybigselect
UNION ALL
SELECT 'Nothing found', NULL, NULL FROM mybigselect
WHERE NOT EXISTS (SELECT * FROM mybigselect)
Note 1: that both rows in the UNION ALL needs to return columns of the same datatype. You can't return a number in the first column of SELECT * FROM mybigselect and "nothing found" in the query after UNION ALL
Note 2: rewrote the query using ANSI-JOIN style syntax.
I would recommend:
WITH cte as (
SELECT a.abc, b.def, c.ghi
FROM comp do JOIN
damp d
ON d.id = co.id JOIN
champ c
ON ch.id = d.id
omp o
ON o.id = ch.id
)
SELECT *
FROM cte
UNION ALL
SELECT 'Some value', NULL, NLL
FROM dual
WHERE NOT EXISTS (SELECT 1 FROM cte)
ORDER BY abc DESC;
Notes:
The value has to be compatible with the type of the column. So, if abc is not a string, then 'Some value' is not appropriate. You haven't provided enough information to determine what value should be in which column.
The ORDER BY should be in the outermost query, not the CTE.
Never use comas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax.
This version uses meaningful table aliases (table name abbreviations) rather than arbitrary letters.

Multiple SELECT statements in MySQL Query

If I have the schemas:
Type(a,b,c,d)
Name(e, b, g)
I am trying to find all the resulting Name's 'E' where the 'D' of the Type is greater than a number that we access using the shared 'B'.
I am trying to understand how to have multiple SELECT statements such as:
SELECT e FROM Name WHERE b = (SELECT b FROM Type WHERE d > 1);
Can someone explain the syntax error and how to do nested SELECT statements or do I have to join the two tables.
Thanks
This can be accomplished using a simple INNER JOIN operation:
SELECT DISTINCT n.e
FROM Name AS n
INNER JOIN Type AS t ON n.b = t.b
WHERE t.d > 1
You can also use EXISTS:
SELECT n.e
FROM Name AS n
WHERE EXISTS (SELECT 1
FROM Type AS t
WHERE n.b = t.b AND t.d > 1)
I think you want to use IN instead of =
SELECT e FROM Name WHERE b IN (SELECT b FROM Type WHERE d > 1);
= to compare one value to another value.
IN to see if a value exist whiten a list of multiple values.

Why use letters in front of each value in MySQL query?

Why would I use letters in front of each value in my query like this?
In the database, each of these values is WITHOUT the letter in front.
SELECT c.client_id, c.client_name, c.contactperson, c.internal_comment,
IF NULL(r.region, 'Alle byer') as region, c.phone, c.email,
uu.fullname as changed_by,
(select count(p.project_id)
from projects p
where p.client_id = c.client_id and (p.is_deleted != 1 or p.is_deleted is null)
) as numProjects
FROM clients c LEFT JOIN users uu ON c.db_changed_by = uu.id
LEFT JOIN regions r ON c.region_id = r.region_id
WHERE (c.is_deleted != 1 or c.is_deleted is null)
I have tried looking it up, but I can't find it anywhere.
When in SQL you need to use more than one table for a query, you can do this:
SELECT person.name, vehicle.id FROM person, vehicle;
OR you can do it smaller, and put like this
SELECT p.name, v.id FROM person p, vehicle v;
It's only for reducing the query length, and it's useful for you
By "letters in front", I assume you mean the qualifiers on the columns c., uu. and so on. They indicate the table where the column comes from. In a sense, they are part of the definition of the column.
This is your query:
SELECT c.client_id, c.client_name, c.contactperson, c.internal_comment,
IF NULL(r.region, 'Alle byer') as region, c.phone, c.email,
uu.fullname as changed_by,
(select count(p.project_id)
from projects p
where p.client_id = c.client_id and (p.is_deleted != 1 or p.is_deleted is null)
) as numProjects
FROM clients c LEFT JOIN
users uu
ON c.db_changed_by = uu.id LEFT JOIN
regions r
ON c.region_id = r.region_id
WHERE (c.is_deleted != 1 or c.is_deleted is null)
In some cases, these are needed. Consider the on clause:
ON c.region_id = r.region_id
If you leave them out, you have:
ON region_id = region_id
The SQL compiler cannot interpret this, because it does not know where region_id comes from. Is it from clients or regions? If you used this in the select, you would have the same issue -- and it makes a difference because of the left join. This is also true in the correlated subquery.
In general, it is good practice to qualify column names for several reasons:
The query is unambiguous.
You (and others) readily know where columns are coming from.
If you modify the query and add a new table/subquery, you don't have to worry about naming conflicts.
If the underlying tables are modified to have new column names that are shared with other tables, then the query will still compile.
Consider you are accessing 2 tables and both have same column name say 'Id', In query you can easily identify those columns using letters like a.Id == d.Id if first table has alias name 'a' and second table 'b'. Or else It would be very difficult to identify which column belongs which table especially when you have common table columns.

Get reference to master select row in nested select

I want my DB to return row under one of two conditions:
The row contains specific value "val" and is of type "sometype"
There is other row, that does have the type "sometype" and the same name as currently checked row.
For this purpose, I made a folowing query:
SELECT c.name, c.value, c.type
FROM `table` AS c
WHERE
c.type='sometype' AND c.value='val'
OR
c.type='othertype' AND
0<(SELECT count(*) FROM `table` AS d WHERE d.name=c.name and c.name='sometype')
Unfortunately, this will return all rows of 'othertype'. I only want these, that have friend with same name and type 'sometype'.
I think the problem is, that I don't know how to get the reference to the values in curently checked row (which I believed to be c.fieldname). I believed d.name = c.name would return all rows that have same name as currently checked row. But the nested select is always >0.
I think this should work for what you are doing:
SELECT c.name, c.type, c.value
FROM test as c
INNER JOIN (SELECT name, type
FROM test
WHERE type = "type1"
AND value = 3) as d
ON c.name = d.name AND c.type = d.type;
SQLFiddle: http://sqlfiddle.com/#!2/63255/1
The inner select gets your #1, where type="sometype" and value="val". Then the outer gets the names, types and values that correspond to the name and type of the inner select, which is your #2.
SELECT c.name
, c.value
, c.type
FROM table c
WHERE (c.type = 'sometype' AND c.value = 'val')
OR (c.type = 'othertype' AND 0< (SELECT COUNT(*) FROM `table` d WHERE d.name = c.name AND c.name='sometype'));
also consider rewriting without the subquery