Frage

Welche Alternativen muss ich mit Hibernate eine Union-Abfrage implementieren? Ich weiß, Hibernate nicht union-Abfragen zur Zeit unterstützen, gerade jetzt den einzigen Weg, ich sehe eine Vereinigung zu machen, ist eine View-Tabelle zu verwenden.

Die andere Option ist schlicht jdbc zu verwenden, aber diese Art, wie ich meine alle example / Kriterien verlieren würde abfragt Goodies, sowie die Hibernate Mapping-Validierung, die führt gegen den Tabellen / Spalten überwintern.

War es hilfreich?

Lösung

Verwenden Sie VIEW. Die gleichen Klassen können auf verschiedene Tabellen / Ansichten abgebildet werden mit Entitätsname, so dass Sie nicht einmal viel von einer Verdoppelung haben. da zu sein, das getan, funktioniert OK.

Plain JDBC ein weiteres verstecktes Problem hat: es von Hibernate-Session-Cache nicht bewusst ist, so dass, wenn etwas bis zum Ende der Transaktion zwischengespeichert wurde und nicht aus dem Ruhezustand Sitzung gespült wird JDBC Abfrage nicht finden. Könnte sehr werden verwirrend manchmal.

Andere Tipps

Sie könnten verwenden id in (select id from ...) or id in (select id from ...)

z. anstelle von Nicht-Arbeits

from Person p where p.name="Joe"
union
from Person p join p.children c where c.name="Joe"

Sie tun können,

from Person p 
  where p.id in (select p1.id from Person p1 where p1.name="Joe") 
    or p.id in (select p2.id from Person p2 join p2.children c where c.name="Joe");

Mindestens mit MySQL finden Sie in Performance-Probleme mit ihm laufen allerdings später. Manchmal ist es einfacher zu machen, verbindet ein armer Mensch auf zwei Abfragen statt:

// use set for uniqueness
Set<Person> people = new HashSet<Person>((List<Person>) query1.list());
people.addAll((List<Person>) query2.list());
return new ArrayList<Person>(people);

Es ist oft besser, zwei einfache Abfragen als ein komplex zu tun.

EDIT:

ein Beispiel zu geben, hier ist die Ausgabe von EXPLAIN der resultierenden MySQL-Abfrage aus der subselect Lösung:

mysql> explain 
  select p.* from PERSON p 
    where p.id in (select p1.id from PERSON p1 where p1.name = "Joe") 
      or p.id in (select p2.id from PERSON p2 
        join CHILDREN c on p2.id = c.parent where c.name="Joe") \G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: a
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 247554
        Extra: Using where
*************************** 2. row ***************************
           id: 3
  select_type: DEPENDENT SUBQUERY
        table: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: Impossible WHERE noticed after reading const tables
*************************** 3. row ***************************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: a1
         type: unique_subquery
possible_keys: PRIMARY,name,sortname
          key: PRIMARY
      key_len: 4
          ref: func
         rows: 1
        Extra: Using where
3 rows in set (0.00 sec)

Am wichtigsten ist, 1. Zeile verwendet keinen Index und hält 200k + Reihen. Schlecht! Die Ausführung dieser Abfrage nahm 0.7s wheres beiden Unterabfragen in den Millisekunden sind.

Ich habe mit Vladimir zustimmen. Ich sah auch in UNION in HQL mit und kann nicht einen Weg, um es finden. Das Seltsame war, dass ich (in der Hibernate FAQ) finden konnte, dass UNION nicht unterstützt wird, Fehlerberichte an UNION betreffend ‚fixed‘ markierte, Newsgruppen von Menschen, die sagen, dass die Aussagen in UNION abgeschnitten würden und andere Newsgruppen von Menschen berichten es funktioniert fein... Nach einem Tag mit ihm von Ausmisten, landete ich meine HQL zurück zur Ebene SQL portieren, aber tun würde es in einer Ansicht in der Datenbank eine gute Option sein. In meinem Fall wurden Teile der Abfrage dynamisch generiert, so dass ich stattdessen die SQL im Code zu bauen hatte.

Ich habe eine Lösung für ein kritisches Szenario (für die ich viel gekämpft) mit Gewerkschaft in HQL.

z. Statt nicht funktioniert: -

select i , j from A a  , (select i , j from B union select i , j from C) d where a.i = d.i 

oder

select i , j from A a  JOIN (select i , j from B union select i , j from C) d on a.i = d.i 

Sie in Hibernate HQL tun konnte ->

Query q1 =session.createQuery(select i , j from A a JOIN B b on a.i = b.i)
List l1 = q1.list();

Query q2 = session.createQuery(select i , j from A a JOIN C b on a.i = b.i)
List l2 = q2.list();

dann kann u beide Liste hinzufügen ->

l1.addAll(l2);

Eine Ansicht ist ein besserer Ansatz, aber da hql typischerweise eine Liste oder Set zurückgibt ... können Sie list_1.addAll (list_2) tun. Völlig kotzen zu einer Vereinigung verglichen, sollte aber funktionieren.

Vielleicht hatte ich ein straight-forward Problem zu lösen. Mein 'zum Beispiel' war mit Hibernate als JPA-Provider in JPA.

ich teilte die drei wählt (zwei in einem zweiten Fall) in mehrere Auswahl und kombinierte mich die Sammlungen zurückgegeben, effektiv eine ‚Vereinigung aller‘ zu ersetzen.

Auch ich habe durch diesen Schmerz gewesen - wenn die Abfrage dynamisch generiert (zum Beispiel Hibernate Criteria), dann konnte ich keinen praktischen Weg finden, es zu tun.

Die gute Nachricht für mich war, dass ich nur Vereinigung war die Untersuchung ein Performance-Problem zu lösen, wenn eine ‚oder‘ in einer Oracle-Datenbank.

Die Lösung Patrick geschrieben (die Ergebnisse programmatisch einen Satz Kombination verwendet wird), während hässlich (zumal ich wollte auch Ergebnisse Paging tun) war ausreichend für mich.


Wie Patrick sagte, die LIST Anhängen s von jedem SELECT wäre eine gute Idee sein, aber denken Sie daran, dass es wie wirkt UNION ALL . Um diese Nebenwirkung zu vermeiden, kontrolliert nur, wenn das Objekt bereits in der endgültigen Sammlung hinzugefügt wird oder nicht. Wenn nein, dann hinzufügen.
Etwas anderes, dass Sie sollten interessiert, ist, dass, wenn Sie eine haben JOIN in jedem SELECT , das Ergebnis wäre eine Liste der Objektarray ( List<Objetc[]> ), so müssen Sie das Objekt nur zu halten über sie iterieren, die Sie benötigen.
Hoffe, dass es funktioniert.

Hier ist ein Sonderfall, aber könnten Sie begeistern Sie Ihre eigene Arbeit um zu erstellen. Das Ziel hier ist es, die Gesamtzahl der Datensätze aus zwei verschiedenen Tabellen zu zählen, in denen Aufzeichnungen ein bestimmten Kriterien erfüllen. Ich glaube, dass diese Technik wird für jeden Fall arbeiten, in dem Sie Daten aus Vorgängen in mehreren Tabellen / Quellen aggregieren müssen.

Ich habe einige spezielle Zwischenklassen-Setup, so dass der Code, der die benannte Abfrage nennt, ist kurz und süß, aber Sie können den Methoden einsetzen, die Sie normalerweise in Verbindung mit benannten Abfragen verwenden, um Ihre Abfrage ausführen.

QueryParms parms=new QueryParms();
parms.put("PROCDATE",PROCDATE);

Long pixelAll = ((SourceCount)Fetch.row("PIXEL_ALL",parms,logger)).getCOUNT();

Wie Sie hier sehen können, die benannte Abfrage beginnt eine aweful viel wie eine Union-Anweisung aussehen:

@Entity
@NamedQueries({
        @NamedQuery(
            name  ="PIXEL_ALL",
            query = "" +
                    "  SELECT new SourceCount(" +
                    "     (select count(a) from PIXEL_LOG_CURR1 a " +
                    "       where to_char(a.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " +
                    "     )," +
                    "     (select count(b) from PIXEL_LOG_CURR2 b" +
                    "       where to_char(b.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " +
                    "     )" +
                    ") from Dual1" +
                    ""
    )
})

public class SourceCount {
    @Id
    private Long   COUNT;

    public SourceCount(Long COUNT1, Long COUNT2) {
        this.COUNT = COUNT1+COUNT2;
    }

    public Long getCOUNT() {
        return COUNT;
    }

    public void setCOUNT(Long COUNT) {
        this.COUNT = COUNT;
    }
}

Ein Teil der Magie hier ist eine Dummy-Tabelle erstellen und einen Datensatz in sie einfügen. In meinem Fall nannte ich es Dual1 weil meine Datenbank ist Oracle, aber ich glaube nicht, dass es wichtig ist, was Sie die Dummy-Tabelle aufrufen.

@Entity
@Table(name="DUAL1")
public class Dual1 {
    @Id
    Long ID;
}

Vergessen Sie nicht, Ihren Dummy-Datensatz einfügen:

SQL> insert into dual1 values (1);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top