Issue converting Access SQL Inner Join Query to mySQL Query - mysql

I am having trouble finding the syntax issue that is causing the following query to give me no results:
SELECT Table1.Country, Table_Data2.Part, Table_Data2.Description, Sum(Table_Data2.Quantity) AS Quantity, Table1.ship_time
FROM Table1 INNER JOIN Table_Data2 ON Table1.CodeValue = Table_Data2.CodeValue
GROUP BY Table1.Country, Table_Data2.Part, Table_Data2.Description, Table1.ship_time
HAVING (((Table_Data2.Part)="BB1234" Or (Table_Data2.Part)="BB-3454") AND ((Table1.ship_time)=Date()));
Which should successfully result in a table that looks like this:
Example of what result should look like
Instead there are no syntax issues that arise nor are there any records that load.
It seems theres a syntax issue in the code above as it does not work in mySQL as it does in MS Access

Few corrections possible:
To get current date in MySQL, use Current_Date(). Date() function in MySQL has different behaviour, as it is used to extract date part out of a date(time) expression.
Parentheses around just field names are unnecessary. Use aliasing in multi table query for code clarity and read ability.
Moreover looking at your conditions in the Having clause, they are more suited to be used in the Where clause. Because they are not aggregated values and you are grouping on these same fields as well. You query will become more performant if you shift them to Where clause, as MySQL will be aggregating on filtered (reduced) data, and thus minimizing temp table space.
Also, you can rewrite multiple OR conditions on same field as IN(...)
You can rewrite as:
SELECT
t1.Country,
t2.Part,
t2.Description,
Sum(t2.Quantity) AS Quantity,
t1.ship_time
FROM Table1 AS t1
INNER JOIN Table_Data2 AS t2
ON t1.CodeValue = t2.CodeValue
WHERE
t2.Part IN ('BB1234', 'BB-3454')
AND t1.ship_time = Current_Date()
GROUP BY
t1.Country,
t2.Part,
t2.Description,
t1.ship_time

Related

SQL Query: Joining on a SUM()

I'm trying to run a query that sums the value of items and then JOIN on the value of that SUM.
So in the below code, the Contract_For is what I'm trying to Join on, but I'm not sure if that's possible.
SELECT `items_value`.`ContractId` as `Contract`,
`items_value`.`site` as `SiteID`,
SUM(`items_value`.`value`) as `Contract_For`,
`contractitemlists`.`Text` as `Contracted_Text`
FROM items_value
LEFT JOIN contractitemlists ON (`items_value`.`Contract_For`) = `contractitemlists`.`Ref`;
WHERE `items_value`.`ContractID`='2';
When I've face similar issues in the past, I've just created a view that holds the SUM, then joined to that in another view.
At the moment, the above sample is meant to work for just one dummy value, but it's intended to be stored procedure, where the user selects the ContractID. The error I get at the moment is 'Unknown Column items_value.Contract_For
You cannot use aliases or aggregate using expressions from the SELECT clause anywhere but HAVING and ORDER BY*; you need to make the first "part" a subquery, and then JOIN to that.
It might be easier to understand, though a bit oversimplified and not precisely correct, if you look at it this way as far as order of evaluation goes...
FROM (Note: JOIN is only within a FROM)
WHERE
GROUP BY
SELECT
HAVING
ORDER BY
In actual implementation, "under the hood", most SQL implementations actually use information from each section to optimize other sections (like using some where conditions to reduce records JOINed in a FROM); but this is the conceptual order that must be adhered to.
*In some versions of MSSQL, you cannot use aliases from the SELECT in HAVING or ORDER BY either.
Your query needs to be something like this:
SELECT s.*
, `cil`.`Text` as `Contracted_Text`
FROM (
SELECT `iv`.`ContractId` as `Contract`
, `iv`.`site` as `SiteID`
, SUM(`iv`.`value`) as `Contract_For`
FROM items_value AS iv
WHERE `iv`.`ContractID`='2'
) AS s
LEFT JOIN contractitemlists AS cil ON `s`.`Contract_For` = cil.`Ref`
;
But as others have mentioned, the lack of a GROUP BY is something to be looked into; as in "what if there are multiple site values."

Sql syntax: select without from clause as subquery in select (subselect)

While editing some queries to add alternatives for columns without values, I accidentally wrote something like this (here is the simplyfied version):
SELECT id, (SELECT name) FROM t
To my surprise, MySQL didn't throw any error, but completed the query giving my expected results (the name column values).
I tried to find any documentation about it, but with no success.
Is this SQL standard or a MySQL specialty?
Can I be sure that the result of this syntax is really the column value from the same (outer) table? The extended version would be like this:
SELECT id, (SELECT name FROM t AS t1 where t1.id=t2.id) FROM t AS t2
but the EXPLAIN reports No tables used in the Extra column for the former version, which I think is very nice.
Here's a simple fiddle on SqlFiddle (it keeps timing out for me, I hope you have better luck).
Clarification: I know about subqueries, but I always wrote subqueries (correlated or not) that implied a table to select from, hence causing an additional step in the execution plan; my question is about this syntax and the result it gives, that in MySQL seems to return the expected value without any.
What you within your first query is a correlated subquery which simply returns the name column from the table t. no actual subquery needs to run here (which is what your EXPLAIN is telling you).
In a SQL database query, a correlated subquery (also known as a
synchronized subquery) is a subquery (a query nested inside another
query) that uses values from the outer query.
https://en.wikipedia.org/wiki/Correlated_subquery
SELECT id, (SELECT name) FROM t
is the same as
SELECT id, (SELECT t.name) FROM t
Your 2nd query
SELECT id, (SELECT name FROM t AS t1 where t1.id=t2.id) FROM t AS t2
Also contains correlated subquery but this one is actually running a query on table t to find records where t1.id = t2.id.
This is the default behavior for the SQL language and it is defined on the SQL ANSI 2011 over ISO/IEC 9075-1:2011(en) documentation. Unfortunately it is not open. This behavior is described on the section 4.11 SQL-Statements.
This behavior happens because the databases process the select comand without the from clause, therefore if it encounters:
select id, (select name) from some
It will try to find that name field as a column of the outer queries to process.
Fortunately I remember that some while ago I've answered someone here and find a valid available link to an SQL ANSI document that is online in FULL but it is for the SQL ANSI 99 and the section may not be the same one as the new document. I think, did not check, that it is around the section 4.30. Take a look. And I really recommend the reading (I did that back in the day).
Database Language SQL - ISO/IEC 9075-2:1999 (E)
It's not standard. In oracle,
select 1, (select 2)
from dual
Throws error, ORA-00923: FROM keyword not found where expected
How can you be sure of your results? Get a better understanding of what the query is supposed to acheive before you write it. Even the exetended version in the question does not make any sense.

MySQL alias replaced by column name when creating view involving subquery

Why is a column alias being replaced by the original column name when I create a view from a script? The script works, the view fails.
The script selects records using an outer query / inner query a.k.a. query / subquery. The subquery is used in the SELECT clause. Each subquery is itself a SELECT clause which becomes a column in the result set. See http://www.techonthenet.com/mysql/subqueries.php.
The alias used inside the subquery's SELECT clauses is replaced with its original column name. The alias used to give the subquery a short name is not replaced.
Here is a meta version so you can see the structure.
select `t1`.`Date` as **`*When*`**,
( select avg(t1.column)
from t1
where `t1.`Date` = `***When***`
) as `Short column name`,
from t1
group by `Date`
order by `Date`
In the View version, with aliases replaced, the subquery becomes;
(
select avg(t1.column)
from t1
where ***`t1.`Date` = `t1.`Date`***
) as `Short column name`,
The effect of this is that the average is calculated across all dates rather than just for the date specified as When in the outer query.
Another script built the same way translates into a view without a problem. The alias is kept.
There is a difference between the clauses used in the bad and good views but it is not obvious to me that it should cause the problem.
The bad view ends with;
group by `Date`
order by `Date`
while the good one ends only with a group by clause.
Another difference is that the column being aliased in the bad view is probably of field type DATETIME, while the one in the good view ia probably one of the INT types. (it's actually week(t1.Date).
Using:
MySQL 5.5
MySQL Workbench 6.0.8
Ubuntu 14.04
The aliases in the SELECT refer to the output of the query block, not to the processing of the query block.
The correct way to do what you want is to use a correlated subquery with table aliases:
select touter.`Date` as **`*When*`**,
(select avg(tinner.column)
from t1 tinner
where `tinner.`Date` = touter.date
) as `Short column name`,
from t1 as touter
group by `Date`
order by `Date`;
I have no idea why the average would be calculated for all the dates. I would expect it to return an error, or perhaps a NULL value. Perhaps your real where clause is t1.Date = Date and you expect MySQL to magically know what the second Date refers to. Don't depend on magic. Use table aliases and be explicit.

mysql max query then JOIN?

I have followed the tutorial over at tizag for the MAX() mysql function and have written the query below, which does exactly what I need. The only trouble is I need to JOIN it to two more tables so I can work with all the rows I need.
$query = "SELECT idproducts, MAX(date) FROM results GROUP BY idproducts ORDER BY MAX(date) DESC";
I have this query below, which has the JOIN I need and works:
$query = ("SELECT *
FROM operators
JOIN products
ON operators.idoperators = products.idoperator JOIN results
ON products.idProducts = results.idproducts
ORDER BY drawndate DESC
LIMIT 20");
Could someone show me how to merge the top query with the JOIN element from my second query? I am new to php and mysql, this being my first adventure into a computer language I have read and tried real hard to get those two queries to work, but I am at a brick wall. I cannot work out how to add the JOIN element to the first query :(
Could some kind person take pity on a newb and help me?
Try this query.
SELECT
*
FROM
operators
JOIN products
ON operators.idoperators = products.idoperator
JOIN
(
SELECT
idproducts,
MAX(date)
FROM results
GROUP BY idproducts
) AS t
ON products.idproducts = t.idproducts
ORDER BY drawndate DESC
LIMIT 20
JOINs function somewhat independently of aggregation functions, they just change the intermediate result-set upon which the aggregate functions operate. I like to point to the way the MySQL documentation is written, which hints uses the term 'table_reference' in the SELECT syntax, and expands on what that means in JOIN syntax. Basically, any simple query which has a table specified can simply expand that table to a complete JOIN clause and the query will operate the same basic way, just with a modified intermediate result-set.
I say "intermediate result-set" to hint at the mindset which helped me understand JOINS and aggregation. Understanding the order in which MySQL builds your final result is critical to knowing how to reliably get the results you want. Generally, it starts by looking at the first row of the first table you specify after 'FROM', and decides if it might match by looking at 'WHERE' clauses. If it is not immediately discardable, it attempts to JOIN that row to the first JOIN specified, and repeats the "will this be discarded by WHERE?". This repeats for all JOINs, which either add rows to your results set, or remove them, or leaves just the one, as appropriate for your JOINs, WHEREs and data. This process builds what I am referring to when I say "intermediate result-set". Somewhere between starting and finishing your complete query, MySQL has in it's memory a potentially massive table-like structure of data which it built using the process I just described. Only then does it begin to aggregate (GROUP) the results according to your criteria.
So for your query, it depends on what specifically you are going for (not entirely clear in OP). If you simply want the MAX(date) from the second query, you can simply add that expression to the SELECT clause and then add an aggregation spec to the end:
SELECT *, MAX(date)
FROM operators
...
GROUP BY idproducts
ORDER BY ...
Alternatively, you can add the JOIN section of the second query to the first.

mysql query join doesnt work but sql "where" does

i am trying to run a join query on mysql i am using following query:
SELECT `Reservation`.`id`
FROM `reservations` AS `Reservation`
LEFT JOIN rates ON Reservation.postal_code=rates.postal_code
this gives my results only for "Reservation" table, and no results for the "rates" table at all, but the following query works fine
SELECT `Reservation`.`id`, rates.id
FROM `reservations` AS `Reservation`, rates
WHERE Reservation.postal_code = rates.postal_code
i am unsure what am i doing wrong, can someone please help?
edit
I was using cakephp and this is just a modified version of a query generated by cakephp and it didnt specify the fields in "select" case so i thought it isn't needed.
You have to include them in the SELECT
SELECT `Reservation`.`id`, rates.*
FROM `reservations` AS `Reservation`
LEFT JOIN rates ON Reservation.postal_code=rates.postal_code
In your second query you have rates.id, that is including it.
NOTE: Don't use the kind of join from the second query you showed us. That's a cross join (theta join) and will make your query go really slow. Always use JOINS.
The first query returns only a single column, id, from reservations. Are you expecting to see data from rates as well? You must mention those columns after the keyword SELECT.
The second query includes the column id from rates.
If you modify the queries so they return the same list of columns they will produce similar (but not identical results). They will still differ in that the second query may return fewer rows — it will not include reservations with 0 corresponding rates (because it uses an INNER JOIN).
The first query isn't selecting from the Rates table. Try this:
SELECT `Reservation`.`id`, `rates`.`id`
FROM `reservations` AS `Reservation`
LEFT JOIN rates ON Reservation.postal_code=rates.postal_code