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
Related
I have a query in which IN operator is used but that query is very slow in production environment.
This is my query
SELECT col1 FROM table_name WHERE col2 IN (251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,
270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,1,2,3,4,5,6,7,8,9,10,11,12,13,14) AND col3 > '1' AND col4 = 1 GROUP BY col1;
I tried find in set but still it is slow, I used composite indexing with the same order of columns as I wrote in where clause, its query cost 151630.44, filter 100 and table contain million of records.
I am expecting to get its query cost as small as possible that is, 1 or 2 and filter 100.
In tends to be slower than comparison. Seeing that your values appear to be largely sequential, try something like
SELECT col1
FROM table_name
WHERE ((col2 >=1 AND Col2 <=14) or (Col2 >=251 AND Col2 <=298))
AND col3 > '1' AND col4 = 1
GROUP BY col1;
I am having the following table say "A"
"column1" "column2"
1 arafath#gmail.com
2 ram#gmail.com;arafath#gmail.com
3 tom#gmail.com
I want to get the records with the following condition.
Condition1:
If the column value exist in the any of the row, it will retrieve the matched rows
Condition2:
If the column value doesn't match with any of the row, it wants to retrieve all the rows
Eg: column2 = "ram#gmail.com"
Output should be "row 2"
Eg: column2 = "arafath#gmail.com"
Output should be "row 1, row 2"
Eg: column2 = "xxx#gmail.com" (Unmatched column)
Output should be all the rows (row 1, row 2, row 3)
Please help me out to solve the problem.
Thanks in advance.
Please try the below one.
SELECT col1, col2
FROM yourTable
where ( not exists (Select col2
FROM yourTable where col2 like 'xxx#gmail.com')
or col2 like 'xxx#gmail.com');
We can try using a union here:
SELECT col1, col2
FROM yourTable
WHERE col2 REGEXP '[[:<:]]ram#gmail.com[[:>:]]'
UNION ALL
SELECT col1, col2
FROM yourTable
WHERE col2 NOT REGEXP '[[:<:]]ram#gmail.com[[:>:]]' AND
NOT EXISTS (SELECT 1 FROM yourTable WHERE col2 REGEXP '[[:<:]]ram#gmail.com[[:>:]]');
Demo
The above strategy is that the first half of the union returns the matching record, if it exists. The second half of the union then returns all other records, but only if on match were found in the first half of the union. If a match were found, then the WHERE clause in the second half of the union would fail, and would return nothing.
Also, please note that storing comma separated (or semicolon separated) data in your MySQL tables is generally bad practice. I had to use REGEXP to get around this problem, but ideally if each email had a separate row, we would only need to use = equality.
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
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.
MY base table have two colums assume col1,col2.
col1 have id, col2 have many comma seprated values colm1 is primary key.
like
col1 col2
---------------------
123 (22,34,12)
124 (45,67,11)
Now i have another table which is in normalized form of the first one like
col1 col2
---------------
123 22
123 34
123 12
124 45
124 67
Now the question is that i want to check that my second table have exect data of first table or not.
And if not then how to find that error.
( i need to show the extra row of second table and missing row of second table seperately )
Something liket that. But unverified
select col1, col2 from old_table
left outer join (select col1, group_concat(col2 separator ',') as col2
from new_table
group by col1) as new_table
on new_table.col1 = old_table.col1 and new_table.col2 = old_table.col2
Get a cursor or recordset and you will then do a loop of all records from table 1,
rs_col1 = id
rs_col2 = the comma seperated values
for each record in rs
select * from table_2 where id = rs_col1 and table_2.col2 not in (rs_col2)
loop
I think your unnormalized data is not quite useful, as the data is not ordered so you can't use a group_concat. However, you might be able to find a solution by using find_in_set and counting the amount of matches of col2 (normalized table) in col2 (unnormalized table) grouped by col1. You will then have to make sure that amount of matches is equal to the amount of elements in the multivalued cell.
Thanx to everbody for suggestions.
I got my solution through this query
select * table1 as a
join table2 as b
on a.col1=b.col1
where a.col2 not like concat('%',b.col2,'%')