Allen,

Het is de bedoeling dat een 'closest event' en de daarop volgende worden weergeven.
Ik heb 2 tabellen. Één moet gewoon 'gejoint' zijn en de andere bevat de datums datum_start en datum_end.
Nou wil ik de data die het dichtst bij nu ligt (of een eigen datum) of wat in ieder geval tussen start en end valt. Maar ook de daarop volgende.
Dus nu en volgende. Zoiets als Nu&Straks van een tvgids.
Lastig uitgelegd, maar kan iemand me op weg helpen?


    $sql = "
	SELECT
		ch.id,
		ch.name,
		ch.name_short,
		pr.channel_id,
		pr.db_id,
		pr.titel,
		pr.datum_start,
		pr.datum_end
	FROM
		" .  TABLE_PREFIX . "channels AS ch
	LEFT JOIN
		" . TABLE_PREFIX . "programs AS pr
		ON ch.id = pr.channel_id
	WHERE
		pr.titel IS NOT NULL
		AND (
		CURRENT_DATE BETWEEN
			pr.datum_start
		AND
			pr.datum_end
		OR
			pr.datum_start =
			(
				SELECT
					MIN(pr.datum_start)
					FROM
						" . TABLE_PREFIX . "programs
				WHERE
					pr.datum_start > CURRENT_DATE
			)
		)
	";

Geeft error: SQLSTATE[HY000]: General error: 1111 Invalid use of group function

Bvd
Als je die subquery nu eens los uitvoert eenmalig voordat je deze query aanroept. Het resultaat ervan voeg je gewoon in. Werkt het dan wel goed? Ik kan me namelijk voorstellen dat die subquery veel te vaak aangeroepen gaat worden op deze manier (namelijk, voor elke rij).
> Ik kan me namelijk voorstellen dat die subquery veel te vaak aangeroepen gaat worden op deze manier (namelijk, voor elke rij).

Hm, als die die select op elke rij doet dan is ie er wel druk mee ja :)
Is er een andere manier?


	$sql = "
		SELECT
			pr.titel,
			pr.datum_start,
			pr.datum_end
		FROM
				" . TABLE_PREFIX . "programs AS pr
		WHERE
			pr.datum_start > CURRENT_DATE
		ORDER BY
			pr.datum_start ASC
		LIMIT 1
	";


Geeft als output:
2014-05-14 00:01:00-2014-05-14 03:14:00

Ook niet helemaal wat het zijn moet dus.
Als de programma's opeenvolgend zijn:

SELECT
	ch.id,
	ch.name,
	ch.name_short,
	np.titel np_titel,
	np.datum_start np_start,
	np.datum_end np_end,
	ne.titel ne_titel,
	ne.datum_start ne_start,
	ne.datum_end ne_end
FROM
	channels ch
INNER JOIN
	programs np
	ON ch.id = np.channel_id AND NOW() BETWEEN np.datum_start AND np.datum_end
INNER JOIN
	programs ne
	ON ch.id = ne.channel_id AND np.datum_end = ne.datum_start
is CURRENT_DATE niet alleen een datum? Met NOW() gaat 't ietsjes beter, maar hij gaat eentje te ver..

WHERE
			pr.datum_start >= NOW()


Nu: 11:51
2014-05-14 11:52:00-2014-05-14 11:54:00
2014-05-14 11:53:00-2014-05-14 12:01:00

Nu: 11:52
2014-05-14 11:53:00-2014-05-14 12:01:00
2014-05-14 11:54:00-2014-05-14 12:30:00
Waarom is dat niet wat het moet zijn? Merk op dat CURRENT_DATE alleen de datum teruggeeft, niet de tijd!

Wat je wellicht kan doen is die subquery ombouwen tot een join en aan de hand daarvan filteren. Dan doe je de berekening maar 1 keer in elk geval. Overigens of het op die manier in een subquery echt voor elke rij gebeurt weet ik niet, maar dat is wel mijn vermoeden.

    SELECT
        ch.id,
        ch.name,
        ch.name_short,
        pr.channel_id,
        pr.db_id,
        pr.datum_start,
        pr.datum_end
    FROM
        " .  TABLE_PREFIX . "channels AS ch
    LEFT JOIN
        " . TABLE_PREFIX . "programs AS pr
        ON ch.id = pr.channel_id
    INNER JOIN (
        SELECT
           datum_start
        FROM
           " . TABLE_PREFIX . "programs
        WHERE
           datum_start > CURRENT_DATE
        ORDER BY
           datum_start ASC
        LIMIT 1
    ) a ON pr.datum_start = a.datum_start;

Snelle ombouw, zo'n omzetting van subquery naar join kan nogal eens wat anders zijn dan je in eerste instantie denkt, maar volgens mij zou dit moeten kunnen.


Toevoeging op 14/05/2014 11:56:28:

Alweer te laat :-)


Nu: 11:52

Het is bijna nooit 11:52:00, maar bijna altijd een paar seconden meer ;-)
> Het is bijna nooit 11:52:00, maar bijna altijd een paar seconden meer ;-)

ha ha ;) bedankt voor je voorbeeld!

@Ger; Ja voorbeeld lijkt helemaal te werken! Maar heb je nou eigenlijk gedaan?
Ik join eerst programs met als extra voorwaarde dat het nu bezig moet zijn (np = now_playing)
Daarna join ik programs (ne=next) nog eens met als extra voorwaarde dat de eindtijd van now_playing overkomt met de starttijd van next.

Je hebt alleen een 'probleem' als er op dit moment geen programma bezig is.
Nice :) Bedankt!
Dit betekent wel dat ik alle velden dubbel moet ophalen (Er zijn er nog meer)? Eenmaal voor np en eenmaal voor ne. Maar dat lijkt me niet zo'n performance probleem.

> Je hebt alleen een 'probleem' als er op dit moment geen programma bezig is.
Dat heb ik nu nog niet, maar zou natuurlijk ooit kunnen voorkomen. Ik kan natuurlijk in PHP even controleren of ie is geset en niet leeg is.
Als er voor één van beide geen programma is, wordt er niks weergegeven?
>>Dit betekent wel dat ik alle velden dubbel moet ophalen (Er zijn er nog meer)? Eenmaal voor np en eenmaal voor ne. Maar dat lijkt me niet zo'n performance probleem.

Het aantal kolommen in de SELECT heeft geen noemenswaardige invloed op de performance

>>Als er voor één van beide geen programma is, wordt er niks weergegeven?
Klopt.

Het kan wel met een left join, maar dan moet de tweede join met een subquery.

Bedankt. We laten het voorlopig zo :) Mocht het gebeuren dat het problemen oplevert zie ik dat tegen die tijd wel.

Reageren