Re: Impossible join?

2005-07-18 Thread Dawid Kuroczko
On 7/16/05, Jonathan Mangin <[EMAIL PROTECTED]> wrote:
> Hello all,
> 
> I'm storing data from a series of tests throughout each
> 24-hour period.  I thought to create a table for each test.
> (There are six tests, lots more cols per test, and many
> users performing each test.)
> 
> select test1.date, test1.time, test2.date, test2.time from
> test1 left join test2 on test2.date=test1.date where
> test1.date between '2005-07-01' and '2005-07-16' and
> uid='me';
> 
> ++--++--+
> | date   | time | date   | time |
> ++--++--+
> | 2005-07-13 | 6:30 | 2005-07-13 | 7:30 |
> | 2005-07-14 | 6:32 | 2005-07-14 | 7:45 |
> | 2005-07-15 | 6:30 | 2005-07-15 | 7:42 |
> | 2005-07-16 | 6:35 | NULL   | NULL |
> ++--++--+
> 
> Is there a join, or some other technique, that would
> return (nearly) these same results if test1 (or any test)
> has not been performed?  Using 4.1.11.

You would need a full outer join, but MySQL doesn't support it... :(

You need some way to hack around it.  Maybe ditch the JOIN clauses
and join tables in application, for instance using hashes?

   Regards,
  Dawid

--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/[EMAIL PROTECTED]



RE: Impossible join?

2005-07-18 Thread Gordon Bruce
Here is one way. 

Some time ago I set up a table named count with one field named count
and built 5000 rows of incrementing values . 


I think I originally populated it by originally createing it with a 2nd
field 

CREATE TABLE `count` (
  `count` int(10) unsigned NOT NULL auto_increment, 
  `addr_ID` int(10) NULL, <<<<<<<<<<<<<<<< this field does not really
matter 
  PRIMARY KEY  (`count`)
) ENGINE=InnoDB DEFAULT CHARSET=;

and then doing something like 

INSERT INTO count(addr_ID) 
SELECT  addr_ID <<<<<<< any primary key out of any table with > 5000
entries
FROM   addresses
LIMIT 5000;

and then droping the 2nd field.

Just put an INSERT in front of the select and set the value = to the #
of dates you want to populate and the set value to 1 day pior to where
you want to start. 

mysql> set @d:='2004-12-31 00:00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select  @d:[EMAIL PROTECTED] + interval 1 day as date from count where 
count <=
10;
+-+
| date|
+-+
| 2005-01-01 00:00:00 |
| 2005-01-02 00:00:00 |
| 2005-01-03 00:00:00 |
| 2005-01-04 00:00:00 |
| 2005-01-05 00:00:00 |
| 2005-01-06 00:00:00 |
| 2005-01-07 00:00:00 |
| 2005-01-08 00:00:00 |
| 2005-01-09 00:00:00 |
| 2005-01-10 00:00:00 |
+-+
10 rows in set (0.00 sec)
-Original Message-
From: Jonathan Mangin [mailto:[EMAIL PROTECTED] 
Sent: Monday, July 18, 2005 8:03 AM
To: Michael Stassen
Cc: mysql@lists.mysql.com
Subject: Re: Impossible join?


> Jonathan Mangin wrote:
>
>> Hello all,
>>
>> I'm storing data from a series of tests throughout each
>> 24-hour period.  I thought to create a table for each test.
>> (There are six tests, lots more cols per test, and many
>> users performing each test.)
>
> But each test is performed no more than once per day by a given user?

Correct.
>
>> select test1.date, test1.time, test2.date, test2.time from
>> test1 left join test2 on test2.date=test1.date where
>> test1.date between '2005-07-01' and '2005-07-16' and
>> uid='me';
>
> Something is strange here.  Doesn't uid exist in both tables?  I'll
assume 
> it does.

Oops. Also correct.
>
>> ++--++--+
>> | date   | time | date   | time |
>> ++--++--+
>> | 2005-07-13 | 6:30 | 2005-07-13 | 7:30 |
>> | 2005-07-14 | 6:32 | 2005-07-14 | 7:45 |
>> | 2005-07-15 | 6:30 | 2005-07-15 | 7:42 |
>> | 2005-07-16 | 6:35 | NULL   | NULL |
>> ++--++--+
>>
>> Is there a join, or some other technique, that would
>> return (nearly) these same results if test1 (or any test)
>> has not been performed?  Using 4.1.11.
>>
>> TIA,
>> Jon
>

[ SNIP! ]


> A better solution would be to add a table:
>
>   CREATE TABLE `testdates` (`date` date default NULL,
>  UNIQUE KEY `date_idx` (`date`)
>);
>
> Insert one row into testdates for each day.  Now you can use something

> like this:
>
>   SELECT testdates.date, test1.time AS 'Test 1', test2.time AS 'Test
2'
>   FROM testdates
>   LEFT JOIN test1 on testdates.date = test1.date AND test1.uid = 'me'
>   LEFT JOIN test2 on testdates.date = test2.date AND test2.uid = 'me'
>   WHERE testdates.date BETWEEN '2005-07-11' AND '2005-07-16';
>
> ++--+--+
> | date   | Test 1   | Test 2   |
> ++--+--+
> | 2005-07-11 | NULL | NULL |
> | 2005-07-12 | NULL | 07:28:00 |
> | 2005-07-13 | 06:30:00 | 07:30:00 |
> | 2005-07-14 | 06:32:00 | 07:45:00 |
> | 2005-07-15 | 06:30:00 | 07:42:00 |
> | 2005-07-16 | 06:35:00 | NULL |
> ++--+--+
> 6 rows in set (0.01 sec)
>
> Much better, don't you think?  This generalizes pretty well, too.
>
>   SELECT testdates.date,
>  test1.time AS 'Test 1',
>  test2.time AS 'Test 2',
>  test3.time AS 'Test 3',
>  test4.time AS 'Test 4'
>   FROM testdates
>   LEFT JOIN test1 on testdates.date = test1.date AND test1.uid = 'me'
>   LEFT JOIN test2 on testdates.date = test2.date AND test2.uid = 'me'
>   LEFT JOIN test3 on testdates.date = test3.date AND test3.uid = 'me'
>   LEFT JOIN test4 on testdates.date = test4.date AND test4.uid = 'me'
>   WHERE testdates.date BETWEEN '2005-07-11' AND '2005-07-16';
>
> ++--+--+--+---

Re: Impossible join?

2005-07-18 Thread Jonathan Mangin



Jonathan Mangin wrote:


Hello all,

I'm storing data from a series of tests throughout each
24-hour period.  I thought to create a table for each test.
(There are six tests, lots more cols per test, and many
users performing each test.)


But each test is performed no more than once per day by a given user?


Correct.



select test1.date, test1.time, test2.date, test2.time from
test1 left join test2 on test2.date=test1.date where
test1.date between '2005-07-01' and '2005-07-16' and
uid='me';


Something is strange here.  Doesn't uid exist in both tables?  I'll assume 
it does.


Oops. Also correct.



++--++--+
| date   | time | date   | time |
++--++--+
| 2005-07-13 | 6:30 | 2005-07-13 | 7:30 |
| 2005-07-14 | 6:32 | 2005-07-14 | 7:45 |
| 2005-07-15 | 6:30 | 2005-07-15 | 7:42 |
| 2005-07-16 | 6:35 | NULL   | NULL |
++--++--+

Is there a join, or some other technique, that would
return (nearly) these same results if test1 (or any test)
has not been performed?  Using 4.1.11.

TIA,
Jon




[ SNIP! ]



A better solution would be to add a table:

  CREATE TABLE `testdates` (`date` date default NULL,
 UNIQUE KEY `date_idx` (`date`)
   );

Insert one row into testdates for each day.  Now you can use something 
like this:


  SELECT testdates.date, test1.time AS 'Test 1', test2.time AS 'Test 2'
  FROM testdates
  LEFT JOIN test1 on testdates.date = test1.date AND test1.uid = 'me'
  LEFT JOIN test2 on testdates.date = test2.date AND test2.uid = 'me'
  WHERE testdates.date BETWEEN '2005-07-11' AND '2005-07-16';

++--+--+
| date   | Test 1   | Test 2   |
++--+--+
| 2005-07-11 | NULL | NULL |
| 2005-07-12 | NULL | 07:28:00 |
| 2005-07-13 | 06:30:00 | 07:30:00 |
| 2005-07-14 | 06:32:00 | 07:45:00 |
| 2005-07-15 | 06:30:00 | 07:42:00 |
| 2005-07-16 | 06:35:00 | NULL |
++--+--+
6 rows in set (0.01 sec)

Much better, don't you think?  This generalizes pretty well, too.

  SELECT testdates.date,
 test1.time AS 'Test 1',
 test2.time AS 'Test 2',
 test3.time AS 'Test 3',
 test4.time AS 'Test 4'
  FROM testdates
  LEFT JOIN test1 on testdates.date = test1.date AND test1.uid = 'me'
  LEFT JOIN test2 on testdates.date = test2.date AND test2.uid = 'me'
  LEFT JOIN test3 on testdates.date = test3.date AND test3.uid = 'me'
  LEFT JOIN test4 on testdates.date = test4.date AND test4.uid = 'me'
  WHERE testdates.date BETWEEN '2005-07-11' AND '2005-07-16';

++--+--+--+--+
| date   | Test 1   | Test 2   | Test 3   | Test 4   |
++--+--+--+--+
| 2005-07-11 | NULL | NULL | NULL | 08:12:00 |
| 2005-07-12 | NULL | 07:28:00 | 07:14:00 | 08:14:00 |
| 2005-07-13 | 06:30:00 | 07:30:00 | 07:16:00 | 08:29:00 |
| 2005-07-14 | 06:32:00 | 07:45:00 | 07:14:00 | 08:26:00 |
| 2005-07-15 | 06:30:00 | 07:42:00 | 07:19:00 | NULL |
| 2005-07-16 | 06:35:00 | NULL | NULL | NULL |
++--+--+--+--+
6 rows in set (0.00 sec)

Michael


I'm guessing this is a common solution.  Shame on me.

How does one swiftly populate a table with an entire year
(or more) of dates?

Thanks very much,
Jon



--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/[EMAIL PROTECTED]



Re: Impossible join?

2005-07-16 Thread Michael Stassen

Jonathan Mangin wrote:


Hello all,

I'm storing data from a series of tests throughout each
24-hour period.  I thought to create a table for each test.
(There are six tests, lots more cols per test, and many
users performing each test.)


But each test is performed no more than once per day by a given user?


select test1.date, test1.time, test2.date, test2.time from
test1 left join test2 on test2.date=test1.date where
test1.date between '2005-07-01' and '2005-07-16' and
uid='me';


Something is strange here.  Doesn't uid exist in both tables?  I'll assume it 
does.



++--++--+
| date   | time | date   | time |
++--++--+
| 2005-07-13 | 6:30 | 2005-07-13 | 7:30 |
| 2005-07-14 | 6:32 | 2005-07-14 | 7:45 |
| 2005-07-15 | 6:30 | 2005-07-15 | 7:42 |
| 2005-07-16 | 6:35 | NULL   | NULL |
++--++--+

Is there a join, or some other technique, that would
return (nearly) these same results if test1 (or any test)
has not been performed?  Using 4.1.11.

TIA,
Jon


With "test1 LEFT JOIN test2", you get dates where test1 was performed, but not 
test2.  With "test2 LEFT JOIN test1", you would get dates where test2 was 
performed but not test1.  You could combine the two with a UNION to include 
both possibilities.  You'd want to see the results in order by date, so you'd 
have to do a tricky ORDER BY on the UNION.  Given only the tables you 
describe, something like this should (almost) do:


(SELECT test1.date d1, test1.time t1, test2.date d2, test2.time t2
FROM test1
LEFT JOIN test2 ON test1.date=test2.date AND test1.uid=test2.uid
WHERE test1.uid = 'me'
  AND test1.date between '2005-07-01' and '2005-07-16')
  UNION DISTINCT
(SELECT test1.date d1, test1.time t1, test2.date d2, test2.time t2
FROM test2
LEFT JOIN test1 ON test1.date=test2.date AND test1.uid=test2.uid
WHERE test2.uid = 'me'
  AND test2.date between '2005-07-11' and '2005-07-16')
  ORDER BY COALESCE(d1, d2);

++--++--+
| d1 | t1   | d2 | t2   |
++--++--+
| NULL   | NULL | 2005-07-12 | 07:28:00 |
| 2005-07-13 | 06:30:00 | 2005-07-13 | 07:30:00 |
| 2005-07-14 | 06:32:00 | 2005-07-14 | 07:45:00 |
| 2005-07-15 | 06:30:00 | 2005-07-15 | 07:42:00 |
| 2005-07-16 | 06:35:00 | NULL   | NULL |
++--++--+
5 rows in set (0.01 sec)

(COALESCE(list) returns the first non-NULL value in the list.)

Ugly, isn't it?  And the ORDER BY at the end uses filesort, which isn't 
desirable.  Also, did you notice that no test was run on the 11th?  Hard to 
see things which aren't there.  This doesn't generalize very well, either.


A better solution would be to add a table:

  CREATE TABLE `testdates` (`date` date default NULL,
 UNIQUE KEY `date_idx` (`date`)
   );

Insert one row into testdates for each day.  Now you can use something like 
this:

  SELECT testdates.date, test1.time AS 'Test 1', test2.time AS 'Test 2'
  FROM testdates
  LEFT JOIN test1 on testdates.date = test1.date AND test1.uid = 'me'
  LEFT JOIN test2 on testdates.date = test2.date AND test2.uid = 'me'
  WHERE testdates.date BETWEEN '2005-07-11' AND '2005-07-16';

++--+--+
| date   | Test 1   | Test 2   |
++--+--+
| 2005-07-11 | NULL | NULL |
| 2005-07-12 | NULL | 07:28:00 |
| 2005-07-13 | 06:30:00 | 07:30:00 |
| 2005-07-14 | 06:32:00 | 07:45:00 |
| 2005-07-15 | 06:30:00 | 07:42:00 |
| 2005-07-16 | 06:35:00 | NULL |
++--+--+
6 rows in set (0.01 sec)

Much better, don't you think?  This generalizes pretty well, too.

  SELECT testdates.date,
 test1.time AS 'Test 1',
 test2.time AS 'Test 2',
 test3.time AS 'Test 3',
 test4.time AS 'Test 4'
  FROM testdates
  LEFT JOIN test1 on testdates.date = test1.date AND test1.uid = 'me'
  LEFT JOIN test2 on testdates.date = test2.date AND test2.uid = 'me'
  LEFT JOIN test3 on testdates.date = test3.date AND test3.uid = 'me'
  LEFT JOIN test4 on testdates.date = test4.date AND test4.uid = 'me'
  WHERE testdates.date BETWEEN '2005-07-11' AND '2005-07-16';

++--+--+--+--+
| date   | Test 1   | Test 2   | Test 3   | Test 4   |
++--+--+--+--+
| 2005-07-11 | NULL | NULL | NULL | 08:12:00 |
| 2005-07-12 | NULL | 07:28:00 | 07:14:00 | 08:14:00 |
| 2005-07-13 | 06:30:00 | 07:30:00 | 07:16:00 | 08:29:00 |
| 2005-07-14 | 06:32:00 | 07:45:00 | 07:14:00 | 08:26:00 |
| 2005-07-15 | 06:30:00 | 07:42:00 | 07:19:00 | NULL |
| 2005-07-16 | 06:35:00 | NULL | NULL | NULL |
++--+--+--+--+
6 rows in set (0.00 sec)

Michael



--
MySQL General Ma

Impossible join?

2005-07-16 Thread Jonathan Mangin

Hello all,

I'm storing data from a series of tests throughout each
24-hour period.  I thought to create a table for each test.
(There are six tests, lots more cols per test, and many
users performing each test.)

select test1.date, test1.time, test2.date, test2.time from
test1 left join test2 on test2.date=test1.date where
test1.date between '2005-07-01' and '2005-07-16' and
uid='me';

++--++--+
| date   | time | date   | time |
++--++--+
| 2005-07-13 | 6:30 | 2005-07-13 | 7:30 |
| 2005-07-14 | 6:32 | 2005-07-14 | 7:45 |
| 2005-07-15 | 6:30 | 2005-07-15 | 7:42 |
| 2005-07-16 | 6:35 | NULL   | NULL |
++--++--+

Is there a join, or some other technique, that would
return (nearly) these same results if test1 (or any test)
has not been performed?  Using 4.1.11.

TIA,
Jon


--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/[EMAIL PROTECTED]