Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

feeding result of one query into another

I tried to simplify my question to a basic example I wrote down below, the actual problem is much more complex so the below queries might not make much sense but the basic concepts are the same (data from one query as argument to another).

Query 1:

SELECT Ping.ID as PingID, Base.ID as BaseID FROM 
    (SELECT l.ID, mg.DateTime from list l
     JOIN mygroup mg ON mg.ID = l.MyGroup
     WHERE l.Type = "ping"
     ORDER BY l.ID DESC
    ) Ping
    INNER JOIN
    (SELECT l.ID, mg.DateTime from list l
     JOIN mygroup mg ON mg.ID = l.MyGroup
     WHERE l.Type = "Base"
     ORDER BY l.ID DESC
    ) Base
    ON Base.DateTime < Ping.DateTime
    GROUP BY Ping.ID
    ORDER BY Ping.ID DESC;

+--------+--------+
| PingID | BaseID |
+--------+--------+
|     11 |     10 |
|      9 |      8 |
|      7 |      6 |
|      5 |      3 |
|      4 |      3 |
+--------+--------+

// from below I need to replace 11 by PingID above and 10 by BaseID above then the results to show up on as third column above (0 if no results, 1 if results)

Query 2:

SELECT * FROM 
    (SELECT sl.Data FROM list l 
     JOIN sublist sl ON sl.ParentID = l.ID
    WHERE l.Type = "ping" AND l.ID = 11) Ping
    INNER JOIN
    (SELECT sl.Data FROM list l 
     JOIN sublist sl ON sl.ParentID = l.ID
    WHERE l.Type = "base" AND l.ID = 10) Base
    ON Base.Data < Ping.Data;

How can I do this? Again I'm not sure what kind of advice I will receive but please understand that the Query 2 is in reality over 200 lines and I basically can't touch it so I don't have so much flexibility as I'd like and ideally I'd like to get this working all in SQL without having to script this.

CREATE DATABASE lookback;
use lookback;

CREATE TABLE mygroup (
ID                          BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
DateTime                    DateTime    
) ENGINE=InnoDB;

CREATE TABLE list (
ID                          BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Type                        VARCHAR(255),
MyGroup                     BIGINT NOT NULL,
Data                        INT NOT NULL
) ENGINE=InnoDB;

CREATE TABLE sublist (
ID                          BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ParentID                    BIGINT NOT NULL,
Data                        INT NOT NULL
) ENGINE=InnoDB;

INSERT INTO mygroup (DateTime) VALUES ("2012-03-09 22:33:19"), ("2012-03-09 22:34:19"), ("2012-03-09 22:35:19"), ("2012-03-09 22:36:19"), ("2012-03-09 22:37:19"), ("2012-03-09 22:38:19"), ("2012-03-09 22:39:19"), ("2012-03-09 22:40:19"), ("2012-03-09 22:41:19"), ("2012-03-09 22:42:19"), ("2012-03-09 22:43:19");    
INSERT INTO list (Type, MyGroup, Data) VALUES ("ping", 1, 4), ("base", 2, 2), ("base", 3, 4), ("ping", 4, 7), ("ping", 5, 8), ("base", 6, 7), ("ping", 7, 8), ("base", 8, 3), ("ping", 9, 10), ("base", 10, 2), ("ping", 11, 3);
INSERT INTO sublist (ParentID, Data) VALUES (1, 2), (2, 3), (3, 6), (4, 8), (5, 4), (6, 5), (7, 1), (8, 9), (9, 11), (10, 4), (11, 6);
like image 338
user391986 Avatar asked Dec 28 '22 04:12

user391986


2 Answers

If this were a more flattened query, then there would a straightforward answer.

It is certainly possible to use a derived table as the input to outer queries. A simple example would be:

select 
  data1, 
  (select data3 from howdy1 where howdy1.data1 = greetings.data1) data3_derived
from 
  (select data1 from hello1 where hello1.data2 < 4) as greetings;

where the derived table greetings is used in the inline query. (SQL Fiddle for this simplistic example: http://sqlfiddle.com/#!3/49425/2 )

Following this logic would lead us to assume that you could cast your first query as a derived table of query1 and then recast query2 into the select statement.

For that I constructed the following:

select query1.pingId, query1.baseId,
       (SELECT ping.Data pingData FROM 
         (SELECT sl.Data FROM list l 
            JOIN sublist sl ON sl.ParentID = l.ID
            WHERE l.Type = "ping" AND l.ID = query1.pingId
         ) Ping
         INNER JOIN
         (SELECT sl.Data FROM list l 
            JOIN sublist sl ON sl.ParentID = l.ID
            WHERE l.Type = "base" AND l.ID = query1.baseId
         ) Base
       ON Base.Data < Ping.Data) 
 from 
   (SELECT Ping.ID as PingID, Base.ID as BaseID FROM 
        (SELECT l.ID, mg.DateTime from list l
         JOIN mygroup mg ON mg.ID = l.MyGroup
         WHERE l.Type = "ping"
         ORDER BY l.ID DESC
     ) Ping
     INNER JOIN
     (SELECT l.ID, mg.DateTime from list l
         JOIN mygroup mg ON mg.ID = l.MyGroup
         WHERE l.Type = "Base"
         ORDER BY l.ID DESC
     ) Base
     ON Base.DateTime < Ping.DateTime
     GROUP BY Ping.ID
   )  query1
   order by pingId desc;

where I have inserted query2 into a select clause from query1 and inserted query1.pingId and query1.baseId in place of 11 and 10, respectively. If 11 and 10 are left in place, this query works (but obviously only generates the same data for each row).

But when this is executed, I'm given an error: Unknown column 'query1.pingId'. Obviously, query1 cannot be seen inside the nested derived tables.

Since, in general, this type of query is possible, when the nesting is only 1 level deep (as per my greeting example at the top), there must be logical restrictions as to why this level of nesting isn't possible. (Time to pull out the database theory book...)

If I were faced with this, I'd rewrite and flatten the queries to get the real data that I wanted. And eliminate a couple things including that really nasty group by that is used in query1 to get the max baseId for a given pingId.

You say that's not possible, due to external constraints. So, this is, ultimately, a non-answer answer. Not very useful, but maybe it'll be worth something.

(SQL Fiddle for all this: http://sqlfiddle.com/#!2/bac74/35 )

like image 33
Mike Ryan Avatar answered Jan 08 '23 16:01

Mike Ryan


The simplest way of dealing with this is temporary tables, described here and here. If you create an empty table to store your results (let's call it tbl_temp1) you can to this:

INSERT INTO tbl_temp1 (PingID, BaseID)
SELECT Ping.ID as PingID, Base.ID as BaseID 
FROM ...

Then you can query it however you like:

SELECT PingID, BaseID from tbl_temp1 ...

Edited to add:

From the docs for CREATE TEMPORARY TABLE:

You can use the TEMPORARY keyword when creating a table. A TEMPORARY table is visible only to the current connection, and is dropped automatically when the connection is closed. This means that two different connections can use the same temporary table name without conflicting with each other or with an existing non-TEMPORARY table of the same name. (The existing table is hidden until the temporary table is dropped.)

like image 56
egrunin Avatar answered Jan 08 '23 17:01

egrunin