Linuchs: mySQL: 1241: Operand should contain 1 column(s)

problematische Seite

Moin,

in einem Sub-Select suche ich pro Veranstalter ein zufälliges Audio-Element.

Von diesem brauche ich 4 Werte:

  • album
  • titel
  • url
  • youtube_id (zum Extrahieren der Tonspur)
SELECT
 MAX( CONCAT( trm1.zeit_neu,'|',trm1.id ))   zeit_neu
...
# Zufalls-Media-Titel
,(
SELECT 
 CONCAT( med1.album, '@', med1.titel, '@', med1.url, '@', med1.youtube_id ) -- 2022-08-20 youtube_id
#,med1.album       med_album
#,med1.titel       med_titel
#,med1.url         med_url
#,med1.youtube_id  med_youtube_id
FROM      bia_medien med1
WHERE     med1.adress_id        = adr1.id
AND       med1.erreichbar_kz    = '1'
# keine Weihnachtslieder im Sommer
AND      ( med1.gueltig_von IS NULL
           OR (     SUBSTR(med1.gueltig_von,6)    <= SUBSTR(CURDATE(),6)
                AND SUBSTR(med1.gueltig_bis,6)    >= SUBSTR(CURDATE(),6) )
         )
ORDER BY  RAND()
LIMIT     0,1
)         med_titel_url
FROM ...

Der Not gehorchend habe ich die 4 Werte per CONCAT zusammengefasst und trenne sie später wieder per explode. Wenn ich die auskommentierten Einzelwerte anspreche, kommt obiger Fehler.

Gibt es nur diese „Bastelversion“ mit CONCAT oder kann ich die vier Werte auch einzeln erhalten?

fragt Linuchs

Edit: Ist CONCAT auf eine Anzahl Werte begrenzt?

#CONCAT( med1.album, '@', med1.titel, '@', med1.url, '@', med1.youtube_id ) -- bleibt leer
 CONCAT( med1.album, '@', med1.titel, '@', med1.url ) -- funktioniert
  1. problematische Seite

    Uups, Geheimwissen: Note: If any of the expressions is a NULL value, it returns NULL

    Die Bastelei wird immer abenteuerlicher, aber funktioniert:

     CONCAT(
       IF( med1.album       IS NULL, '', med1.album ),  '@',
       IF( med1.titel       IS NULL, '', med1.titel ),  '@',
       IF( med1.url         IS NULL, '', med1.url ),    '@',
       IF( med1.youtube_id  IS NULL, '', med1.youtube_id )
     )
    

    Bleibt die Frage, ob ich die Werte auch einzeln bekommen kann ohne CONCAT

    1. problematische Seite

      CONCAT(
        IF( med1.album       IS NULL, '', med1.album ),  '@',
        IF( med1.titel       IS NULL, '', med1.titel ),  '@',
        IF( med1.url         IS NULL, '', med1.url ),    '@',
        IF( med1.youtube_id  IS NULL, '', med1.youtube_id )
      )
      

      Naja. Man könnte auch vorbeugen wenn man die Hand auf dem Programm und den Tabellen hat. Ich weiß ja nicht, wie lang Deine Ergebnislisten sind, aber wenn die SEHR lang sind, dann kostet das den Prozessor auf dem Server einige Herzschläge extra.

      Kann man vermeiden:

      UPDATE med1 set album      ='' where album      =NULL;
      ALTER TABLE med1 ALTER album  SET DEFAULT '';
      
      UPDATE med1 set titel      ='' where titel      =NULL;
      ALTER TABLE med1 ALTER titel  SET DEFAULT '';
      
      UPDATE med1 set url        ='' where url        =NULL;
      ALTER TABLE med1 ALTER url  SET DEFAULT '';
      
      UPDATE med1 set youtube_id ='' where youtube_id =NULL;
      ALTER TABLE med1 ALTER youtube_id  SET DEFAULT '';
      

      Und dann das CONCAT() ohne das IF()-Geraffel.

      P.S.

      1. Ich glaube ja auch nicht, dass überhaupt alle Spalten betroffen sind.
      2. Das obige geht natürlich nur, wenn die Spaltentypen als String festgelegt sind.
  2. problematische Seite

    Hi,

    in einem Sub-Select suche ich pro Veranstalter ein zufälliges Audio-Element.

    Von diesem brauche ich 4 Werte:

    Das klingt nicht nach subselect, sondern nach join.

    Edit: Ist CONCAT auf eine Anzahl Werte begrenzt?

    einige SQL-Dialekte haben bei 1000 Parametern ein Limit - ist mir bis jetzt nur bei IN() aufgefallen - concat mit so vielen Parametern hatte ich noch nicht …

    cu,
    Andreas a/k/a MudGuard

    1. problematische Seite

      Das klingt nicht nach subselect, sondern nach join.

      Ich arbeite haufenweise mit joins, muss mal nachdenken, warum ich das hier nicht gemacht habe ... (die Stelle ist uralt, nur das Feld youtube_id neu)

      Vielleicht, weil ich ein ORDER BY RAND benötige? Kann ich per join einen Zufallswert ankoppeln?

      1. problematische Seite

        Hallo Linuchs,

        deine Query ist ohnehin total verquast und dürfte etliche "undefined" Komponenten enthalten.

        • Du mischst eine Aggregatspalte mit einer Nichtaggregatspalte
        • Du referenzierst im Subselect die Spalte adr1.id - auf welche ID soll sich das denn bitte schön beziehen, wenn Du im SELECT eine MAX-Bestimmung machst? Oder steckt im FROM eine Abfrage adr1.id = $someId, so dass die adr1.id für alle Sätze gleich ist?

        Meine Empfehlung wäre, zwei Querys zu machen.

        Zunächst diese:

        SELECT  trm1.zeit_neu, trm1.id, adr1.id
        FROM table1 trm1 JOIN table2 adr1 ON ...
        WHERE ...
        ORDER BY trm1.zeit_neu desc
        LIMIT 1
        

        Ich hab da jetzt irgendeinen JOIN hingeschrieben, das ist nur symbolisch und sieht in deiner Realität sicherlich anders aus.

        Damit bekommst Du den MAX-Wert für zeit_neu und die trm1.id dazu, auf definierte Weise und ohne Stringverkettung. Wenn Du einen Index auf zeit_neu hast, führt diese Aufteilung auch zu einer Beschleunigung, weil er dann den Index dafür nutzen kann. Ob Du die adr1.id auch selektieren musst, hängt von Kontext ab den ich nicht kenne - ich hab sie mal reingeschrieben für den Fall, dass es mehrere adr1.id geben könnte.

        Im zweiten Schritt machst Du dann den Zufalls-Select.

        Das sind zwar zwei Queries, aber man muss nicht alles in einer Query zusammenpressen. Wenn dein SQL Server auf localhost läuft, ist die Abfragelatenz miminal. Wenn er auf einem anderen Server läuft, hast Du ein paar Millisekunden Latenz drin, aber bei einem stark belasteten System wird diese Latenz für die Ausführung anderer Requests genutzt, d.h. der Serverdurchsatz verringert sich nicht. Nur die Antwortzeit für einen einzelnen User, um ein kleines Bisschen. Das ist nicht schlimm. Aus Serversicht geht es Dir um die Optimierung des Durchsatzes, nicht unbedingt um schnellste Antwortzeit für einzelne User.

        Rolf

        --
        sumpsi - posui - obstruxi
  3. problematische Seite

    Hallo Linuchs,

    ein SELECT, mit dem Du einen Wert in die Select-Liste bringen willst, darf immer nur einen Wert liefern, das ist so.

    Wie Mudguard sagte: Du musst einen JOIN machen. Ggf. einen LEFT JOIN.

    Um NULL-Werte auf '' zu zwingen, kannst Du dein IF Konstrukt verwenden oder die IFNULL-Funktion (COALESCE geht auch).

    Dein MAX sieht auch nach einem Hack aus, aber ich glaube, der ist hier ganz elegant.

    Rolf

    --
    sumpsi - posui - obstruxi