Using HAVING clause on function result in select - sql-server-2008

I'm troubled how to use HAVING clause avoiding function calling twice.
here is my qry:
select col1, col2, dbo.someFunction(param1, param2) as col3
from...
where ...
group ...
having dbo.someFunction(param1, param2) > 0
if I wrote
having col3 > 0
server sais: Invalid column name 'col3 '.
Is there a way to use HAVING in shown situation without calling function dbo.someFunction twice?
EDIT
my execution plan with having:
and without having (commented):
Select without function in select:

Are you sure it is calling it twice?
I get the same execution plan from the following two queries
select enumID
from docSVenum1
group by enumID
having COUNT(*) > 2000
select enumID, count(*) as ccount
from docSVenum1
group by enumID
having COUNT(*) > 2000

In order not to call the function twice but refer to the result that is returned in column col3 you'll need another SELECT statement around your query, like below.
SELECT col1,
col2,
col3
FROM
(SELECT col1,
col2,
dbo.someFunction(param1, param2) AS col3
FROM ...
WHERE... ) AS Result
GROUP BY ...
HAVING col3 > 0
You can't reference a column by its alias on the same "nesting level" of the SELECT, which is why you'll have to surround your initial result in another SELECT statement, from which you will be able to reference the column by its alias.

Related

How to build a sequence of values by combining two columns?

I am looking to get a sequence of values by combining two columns that are linked using some random ids:
Table (col2 and col3 are linked)
col1 col2 col3
aa a144 d653
bb z567 a144
cc d653 h999
dd y678 z567
The two columns (col2 and col3), this is like a chain that is forming up.
The result I am looking for is a sequence from start to end:
sequence
y678
z567
a144
d653
h999
Explanation:
The sequence starts at row 4 (dd,y678,z567), followed by row 2 (bb,z567,a144) and so on.
Col3 id is the reference for the Col2 id, to decide the next element.
What you're looking for is a recursive query.
Assuming your table is called data, you do it like this:
WITH RECURSIVE query(id) AS (
SELECT col2
FROM data
WHERE col1 = 'dd' -- Select the initial row here
UNION ALL
SELECT data.col3
FROM data
INNER JOIN query on query.id = data.col2
)
SELECT *
FROM query;
Tested snippet available here: https://onecompiler.com/mysql/3xvj2a47v.
This syntax works in MySQL version 8 and up. If your version is lower, first thing I would recommend is to update it, if possible. If not possible, consult this answer for a workaround using MySQL 5: https://stackoverflow.com/a/33737203/2979473.
you are going to have to use a cursor..
https://www.mysqltutorial.org/mysql-cursor/
first step will be to select the value from col2 that doesn't exist in col3
then insert the value from col3 where the current variable is in col2
return the results set when the value in col3 is not found in col2
This will only work if there is one start and end value and one distinct path through the chain.
It will also be slow, because this is not how RDBMS databases are designed to work.
I think this query will work for you.
SELECT DISTINCT SEQ
FROM
(
SELECT COL2 SEQ FROM TABLE1
UNION
SELECT COL3 SEQ FROM TABLE1
) ORDER BY 1

Query with GROUP BY and ORDER BY not working when multiple columns in SELECT are chosen

I'm updating an old website and one of the queries isn't working anymore:
SELECT * FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
I noticed if I dropped the GROUP BY it works, but the result set doesn't match the original:
SELECT * FROM tbl WHERE col1 IS NULL ORDER BY col2
So I tried reading up on GROUP BY in the docs to see what might be the issue, and it seemed to suggest not using * to select all the fields, but explicitly using the column name so I tried it with just the column that was being ordered and grouped:
SELECT col2 FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
Which works but after looking through the code the query requires 2 columns in the query so whoever added * was overdoing it, but if I add that column produces an error, similarly adding a third column produces the same error:
SELECT col2, col3 FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
SELECT col1, col2, col3 FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
Can anyone tell me why this last query doesn't work? I can't decipher why from the docs, but this is the minimum query required to get the result set I need.
Running the query in Adminer I get this error
Error in query (1055): Expression #2 of SELECT list is not in GROUP BY
clause and contains nonaggregated column 'name.table.column'
which is not functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
You need to be careful when you use GROUP BY. Once you understand what GROUP BY does, you will know the issue yourself. It does an aggregation on your data or in other words, it reduces your data by doing some operation on the raw entries and creating new reduced number of entries on which some aggregation function has been applied(SUM, COUNT, AVG, etc.)
The fields you provide in the GROUP BY clause represents the level of aggregation/roll-up you are going for.
SELECT col2, col3 FROM tbl WHERE col1 IS NULL GROUP BY col1 ORDER BY col1
Here you are trying to do the aggregation at col1 level, meaning that for every distinct value present in column col1, there will be some operation done on some other columns you provide in SELECT clause(here col2,col3) so that in the output you have non-repeating values in col1 and some rolled-up values of col2 and col3 against each distinct col1 value based on what function you apply(SUM, COUNT, AVG, etc.).
How do you apply this function? That is what is missing in your above query. To solve it, you need to apply some aggregation function on the fields that are present in the SELECT clause but not in GROUP BY clause. Taking an example of SUM, try this:
SELECT SUM(col2), SUM(col3) FROM tbl WHERE col1 IS NULL GROUP BY col1 ORDER BY col1
OR for a better idea, removing WHERE filter and checking the output by running:
SELECT col1, SUM(col2), SUM(col3) FROM tbl GROUP BY col1 ORDER BY col1
Additionally, the reason why your other query
SELECT col2 FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
worked is because you need not apply aggregation to the field(here col2) which is present in the GROUP BY clause.
First of all, when query() returns false, you should find out what the error was. You seem to be using PDO, so I will direct you to this page: http://php.net/manual/en/pdo.error-handling.php
TL;DR - you should enable PDO exceptions, or else you need to write code to check the result of every call to query(), prepare(), and execute() to see if an error occurred. And if so, use errorInfo() to find out the actual error. Doing anything else is flying blind!
Error in query (1055): Expression #2 of SELECT list is not in GROUP BY
clause and contains nonaggregated column 'webvictoria.cats_oct.matchLink'
which is not functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
This is a common issue. See dozens of questions tagged mysql-error-1055.
I guess you just upgraded to MySQL 5.7. MySQL 5.7 enabled strict mode by default, so I guess you just upgraded. Prior to MySQL 5.6, strict mode was optional and not enabled by default.
See: https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
You can't write ambiguous queries. If you GROUP BY col2, which value in the group of rows of each group should be used for col1 and col3? It's ambiguous.
Without strict mode, MySQL chooses an arbitrary row from the group. With strict mode, it reverts to standard SQL behavior, and disallows the ambiguous query. This is how most other brands of SQL database behave, by the way.
To fix it, you must follow this rule: Every column in your select list must be one of:
A column in your GROUP BY clause
A column functionally dependent on the columns in your GROUP BY clause (so there can only be one value)
Used in an aggregate function like MIN(), MAX(), COUNT(), SUM(), AVG(), or GROUP_CONCAT()
Some people choose to disable strict mode in MySQL 5.7 for the sake of "getting the code working again." But it isn't working—it's just giving ambiguous results like it did before MySQL 5.7.
It's better to fix the logic of your queries.
This query:
SELECT *
FROM tbl
WHERE col1 IS NULL
GROUP BY col1
ORDER BY col1;
never really worked. It may have seemed to work, but you were just lucky. You have unaggregated columns in the SELECT. These come from an arbitrary row.
You can do something like this to get values from other columns:
SELECT col1, min(col2), min(col3)
FROM tbl t
WHERE col1 IS NULL AND
GROUP BY col1
ORDER BY col1;
The reason it didn't work is because you need to use one of the selection criteria in the GROUP BY and the ORDER BY. So if you wanted to group by col1, you would need to do this:
SELECT col1, col2, col3
FROM tbl
WHERE
col1 IS NULL
GROUP BY col1
ORDER BY col1
;
Without selecting that field, you are basically saying "Hey go get me every phone number in California" Then after you get that you say "Now order them by first name and group them by last name" and DBMS says "but... I don't have any of that"
try this
SELECT col2, col3 FROM tbl WHERE col1 IS NULL GROUP BY col2, col3 ORDER BY col2, col3

How do I execute a query using INSERT INTO and WITH statement?

INSERT INTO tablename( columnname1, columnname2, columnaname2)
WITH
a AS
SELECT * FROM tablename
WHERE condition
),
b AS
SELECT * FROM tablename
WHERE condition
)
I have a couple lines of query below where I use an DISTINCT statement but would like to know for now whether my query above is correct or not.
WITH? This is going to be introduced in MySQL 8.0. Are you using a preview release? Otherwise you won't be able to use WITH in MySQL.
Anyway: A WITH clause belongs at the beginning of the statement: WITH ... INSERT .... See here: https://dev.mysql.com/doc/refman/8.0/en/with.html.
It seems, however, you are not even using your CTEs a and b. Your CTEs are also lacking parentheses. Your statement should look something like this for instance:
WITH a AS (SELECT * FROM tablename WHERE condition)
, b AS (SELECT * FROM tablename WHERE condition)
INSERT INTO tablename(columnname1, columnname2, columnaname2)
SELECT col1, col2, col3 FROM a
UNION ALL
SELECT col1, col2, col3 FROM b;

When querying multiple tables using UNION ALL the AS keyword only works for the first table

I have a query:
(SELECT col1 AS table1 FROM table1 WHERE col3 IS NOT NULL)
UNION ALL
(SELECT col1 AS table2 FROM table2 WHERE col3 IS NOT NULL)
UNION ALL
(SELECT col1 AS table3 FROM table3 WHERE col3 IS NOT NULL)
However when I process this using PDO and the fetchAll(PDO::FETCH_ASSOC); command, the keys to the array generated all come out as table1 irrespective of the table they are actually from.
Is my syntax incorrect? Thanks!
Your query returns a single column. A single column can only have one name/alias. In a UNION query, the first subquery defines the resulting set's column names.
If you want to specify which table each value has come from, add another column, e.g. like this:
(SELECT col1, 'table1' AS src FROM table1 WHERE col3 IS NOT NULL)
UNION ALL
(SELECT col1, 'table2' FROM table2 WHERE col3 IS NOT NULL)
UNION ALL
(SELECT col1, 'table3' FROM table3 WHERE col3 IS NOT NULL)
That's the SQL specification: The column names of the result set are taken from the first select.
It's just the way it is.
When you think about it, having different column names in subsequent selects makes no sense, because a column name can't change part way through a result set - column names are defined (once) for the (entire) result set.
Yes, this the way it works, the unioned values will have the alias from the column in the first query. Quoted from UNION documentation page:
The column names from the first SELECT statement are used as the
column names for the results returned.
If you didn't need that, give that column the alias you want.

How to alias a field or column in MySQL?

I'm trying to do something like this. But I get an unknown column error:
SELECT SUM(field1 + field2) AS col1, col1 + field3 AS col3 from core
Basically, I want to just use the alias so that I won't need to perform the operations performed earlier. Is this possible in mysql?
select #code:= SUM(field1 + field2), #code+1 from abc;
But, please be aware of the following (from the MySQL 5.6 docs):
As a general rule, other than in SET statements, you should never assign a value to a user variable and read the value within the same statement. For example, to increment a variable, this is okay:
SET #a = #a + 1;
For other statements, such as SELECT, you might get the results you expect, but this is not guaranteed. In the following statement, you might think that MySQL will evaluate #a first and then do an assignment second:
SELECT #a, #a:=#a+1, ...;
However, the order of evaluation for expressions involving user variables is undefined.
So, use at your own risk.
Consider using a subquery, like:
SELECT col1
, col1 + field3 AS col3
FROM (
SELECT field1 + field2 as col1
, field3
from core
) as SubQueryAlias
You can select the alias:
SELECT SUM(field1 + field2) AS col1, (select col1) + field3 AS col3 from core
This works.
select #code:= SUM(field1 + field2), (#code*1) from abc;
#code*1 covert into numeric expression and you can use anywhere like
select #code:= SUM(field1 + field2), (#code*1)+field3 from abc;
Short answer is no:
mysql> select 1 as a, a + 1 as b;
ERROR 1054 (42S22): Unknown column 'a' in 'field list'
postgresql# select 1 as a, a + 1 as b;
ERROR: column "a" does not exist
That said, some SQL implementations allow to use the aliases in where/group by/having clauses, e.g.:
postgresql# select 1 as a group by a; -- 1 row
In case you are using it with aggregate function (group by) and if it doesn't work for you place the calculated column to the end with forward column referecing.
SELECT FNC2(AF), FNC1(A) AS AF, B, C, FROM Table GROUP BY ...
1st one doesn't work due to forward column referencing. Do this instead
SELECT FNC1(A) AS AF, B, C, FNC2((SELECT AF)) FROM Table GROUP BY ...