MySQL Subquery in the same table - mysql

This is my first question. I've trying to deal with this all week long with no success.
I have the following table
ID F1 F2
1 1 10
2 3 5
3 2 8
4 7 10
5 11 20
6 12 18
7 15 20
Please note that the values of the rows 2,3,4 are between the values of the first row.
Then, rows 6 and 7 are between the values of the row 5
I need to create a query that should bring me only rows 1 and 5.
I have tried many kind of queries with no success.
I was expecting the following query to work (among many others) but it did not.
select OL.F1,OL.F2
from borrar OL,
(select F1,F2
from borrar
) IL
where
OL.F1 >= IL.F1
and OL.F2 <= IL.F2
Any ideas?.
Thanks,

You can do this with a self-join. The thing that makes rows 1 and 5 different from the other rows is that there are no rows in the table where F1 is less than Row 1&5's value for F1 and F2 is greater than Row 1&5's value for F2.
SELECT t1.*
FROM datatable t1
LEFT OUTER JOIN datatable t2
on t2.F1<=t1.F1 and t2.F2>=t1.F2 and t1.id<>t2.id
WHERE t2.ID is NULL
Self joins are always a bit confusing. Each row is combined with all other rows to find if there is some other row that "spans" it (i.e. F1 and F2 are equal to or outside it) but need to exclude the row spanning itself. Use an outer join, and search for NULL's to find the rows that have no matches.

This seems like a homework problem...
But, one thing I noticed is that F2-F1 = 9 in both cases. Perhaps using that in the Where clause will do the trick ;)

Related

Mysql find duplicated on the first matched characters

I want to pull out double records on the first matched four characters at the left or at first lines in MySQL.
how to make a SELECT?
id name
1 1111q
2 1111
3 1111asdfgg
4 2222
5 2222ag
6 1111au
7 3333
8 5555
Something like:
id name
2 1111
1 1111q
6 1111au
3 1111asdfgg
4 2222
5 2222ag
select distinct t.*
from the_table t
inner join the_table t2 ON left(t.name,4)=left(t2.name,4) and t.id<>t2.id
Join to the same table by LEFT 4 chars and exclude the same ID
Remove my original answer as misread the question.
What you could do is add one more indexed column with the first 4 characters from string. You'll probably pre-process the strings with some other language. This way you can have working index also. By joining the same table in to calculation with subquery and join. You can then compare the counts. Even better would be if you can add some kind of comparison operator to subquery for searching only certain prefixes.
The solution using left is not bad at all, but it loses power of index when using function around field when comparing.
Here's working example from my solution. You can view the execution plan from the bottom.
http://sqlfiddle.com/#!9/1d9cc/19

Coalesce pulling zero as value

this is driving me crazy!
I have three tables. The first table has a list of all records along with other data (region, dates, etc). The 2nd and 3rd tables have all the hours/cost data, but the 2nd table contains only historical records, and the 3rd table contains newer records. I want my coalesce to try to find a value in the newer records first, but if no record is found, to look in the historic table. For some reason, even though i KNOW there is a value in the historic table, the result of my coalesce is coming in as 0.
Table1
ID Region
1 US
2 US
3 Europe
4 US
5 Europe
6 US
Table2
ID Hours
1 10
2 15
3 20
Table3
ID Hours
4 3
5 7
6 4
So, my statement is written like this:
SELECT
t1.ID,
COALESCE(t3.hours, t2.hours) AS HOURS
FROM table1 t1
LEFT JOIN table2 t2
ON t1.ID=t2.ID
LEFT JOIN table3 t3
ON t1.ID=t3.ID
Now, for some reason, if the value is found in t3 (the newer records) it pulls in the correct value, but if it does not find a value and has to pull in a value from t2, it is pulling in a 0 instead of the actual value. Result looks like this:
ID HOURS
1 0
2 0
3 0
4 3
5 7
6 4
My guess is that it has something to do with the column type in table 2 (I have all column settings as VARCHAR(55), but I can't find any rules around data types in coalesce function about having to use only a certain column type with coalesce.
Appreciate any guidance!
edited to add results for Spencer's inquiry:
ID t2.hours + 0 t2.hours hex(t2.hours) length(t2.hours)
413190 240 240 F0 3
Incorrect joins:
FROM table1 t1
LEFT JOIN table2 t2 ON t1.ID=t2.ID
^
LEFT JOIN table3 t3 ON t1.ID=t2.ID
^
you're joining table 3 using values from table 2
It looks like the evaluation of t2.hours in the COALESCE function is being done in numeric context, and the values stored in the hours column are evaluating to a numeric value of 0.
One quick way to check what numeric that evaluates to is to add a zero, as in the first expression in this query:
SELECT t2.hours + 0
, t2.hours
, HEX(t2.hours)
, LENGTH(t2.hours)
FROM table2 t2
I'm curious what that query shows for one of the rows that's returning a 0 from the COALESCE expression, whether the numeric evaluation is returning 0, and whether there's any leading wonky characters in the column value.

SQL count not return all rows, phpmyadmin add LIMIT but not show it in the query

I have a query:
select lr2.event_id as ce
from data_requests as lr2
group by lr2.event_id,
that returns 88 rows. Then I tried the following:
select count(lr2.event_id) as cc, lr2.event_id as ce
from data_requests as lr2
group by lr2.event_id
but it only returned 25 rows, so I am really puzzled, where did other 63 rows go.
I tried it in sqlfiddle, it seems to work correctly, but on my server it just doesn't, so it must be a setting or something... Feels like the server calculates the count after it select a subset of all group results. weird.
if you want to count the number of rows for each lr2.event_idyou must use count(*) , not count(lr2.event_id) . Remember, you are counting rows.
Function of GROUP BY
The SQL GROUP BY clause is used in collaboration with the SELECT statement to arrange identical/similar/equal data into groups.
Demonstration
If I have table like below, then 1st query will give same output as table definition:
ce
--
1
2
3
4
5
And 2nd query will give output as,
cc |ce
--- ---
1 1
1 2
1 3
1 4
1 5
Since, all are distinct in Table, I got 5 rows! but If some ce values are repetitive as,
ce
--
1
2
1
2
2
then, 2nd query will give output as:
cc |ce
--- ---
2 1
3 2
And here If I get shocked where did other 3 rows go? Then I need to study!
Of course, it's a spoon feeding! OP needs to study about GROUP BY in SQL.
My bad, it seems to be a phpmyadmin problem, I run the query in the phpmyadmin, and it auto added a limit in the end of every query

Limit On Accumulated Column in MySQL

I'm trying to find an elegant way to write a query that only returns enough rows for a certain column to add up to at least n.
For example, let's say n is 50, and the table rows look like this:
id count
1 12
2 13
3 5
4 18
5 14
6 21
7 13
Then the query should return:
id count
1 12
2 13
3 5
4 18
5 14
Because the counts column adds up to n > 50. (62, to be exact)
It must return the results consecutively starting with the smallest id.
I've looked a bit into accumulators, like in this one: MySQL select "accumulated" column
But AFAIK, there is no way to have the LIMIT clause in an SQL query limit on an SUM instead of a row count.
I wish I could say something like this, but alas, this is not valid SQL:
SELECT *
FROM elements
LIMIT sum(count) > 50
Also, please keep in my the goal here is to insert the result of this query into another table atomically in an automated, performance efficient fashion, so please no suggestions to use a spreadsheet or anything that's not SQL compatible.
Thanks
There are many ways to do this. One is by using Correlated Subquery
SELECT id,
count
FROM (SELECT *,
(SELECT Isnull(Sum(count), 0)
FROM yourtable b
WHERE b.id < a.id) AS Run_tot
FROM yourtable a) ou
WHERE Run_tot < 50

MySql - getting a row from latest non-null values in each column

I have a table and I would like to get a row containing all the latest non-null attributes for each column (without combining separate queries for each column, which doesn't seem elegant to me).
Example:
A B C Time
1 a 7 0
NULL NULL 3 1
3 NULL 4 2
NULL NULL 6 3
Result I seek:
A B C
3 a 6
As I said, I know how to select what I want for each column separately, but I was wondering if there's a better way to do it. No need to tax the poor database if it isn't needed.
Probably a better way than this, but it's Monday and I'm not quite conscious yet:
select #a:=null, #b:=null, #c:=null;
select A,B,C from (
select #a:=coalesce(A,#a) as A, #b:=coalesce(B,#b) as B, #c:=coalesce(C,#) as C time
from yourtable
order by time asc
) as y order by time desc limit 1;
Basically, iterate over each row in the database and build up the "latest" value as you go, then reverse the result set and select only the one with the highest time value