Re: SQL join ερώτηση

Aggelos Karalias d_angel at freemail.gr
Fri Mar 27 18:41:48 EET 2009


Καλησπέρα,

αρχικά πιστεύω ότι όλοι συμφωνούμε ότι αυτό που θα έπρεπε να διορθωθεί είναι
το schema, αλλά δυστυχώς είναι πολλές οι φορές που πέφτεις πάνω σε schemata
που έχουν σχεδιαστεί με τα πόδια και για διάφορους λόγους δεν αλλάζουν.
Επίσης δεν μπορείς να έχεις κάποιο expression στο select εκτός από τα
κλασσικά *, operators και aggregate functions. Η λύση που βλέπω είναι αυτή
που προτάθηκε και πριν ...

> George Zarogiannis wrote:
> > Νομίζω ότι όντως ζητάς πολλά από την SQL :)
> >
> > Ο μοναδικός τρόπος που μπορώ να σκεφτώ, υποθέτωντας ότι γράφεις σε
> > κάποια γλώσσα, είναι να διαβάσεις πρώτα τα πεδία των 2 πινάκων και
> > μετά να φτιάξεις δυναμικά το SELECT ώστε να περιέχει κάθε όνομα πεδίου
> > 1 φορά. Το πως θα το κάνεις αυτό, εξαρτάται από τη γλώσσα/βάση που
> > δουλεύεις...

... αλλά με την διαφωνία ότι δεν ζητάς πολλά από την SQL (αλλά σίγουρα ζητάς
άσχημα...)

Αν ξέρεις τους systemικούς πίνακες του rdbms σου μπορείς να τρέξεις κάτι σαν
το παρακάτω (ελπίζω να μην υπάρχουν σοβαροί περιορισμοί στην sqlite). Eπειδή
δεν μπορώ να κάνω δοκιμές σε sqlite, δες αυτό για mysql:

<code>
/* IMPORTANT: set the table and join fields. If join fields are more than
one then the query should change */
/* TODO: include DBNames of the tables in the query to avoid conflicts if
same table names exist on different DBs */
set @tableA = 'TABLEA';
set @tableB = 'TABLEB';
set @tableAJoinField = 'id';
set @tableBJoinField = 'id';

/* get columns  in tableA which does not exist in tableB*/
set @extraColumnsA = (
    select GROUP_CONCAT(column_name) from information_schema.`COLUMNS`
        where table_name = @tableA
            and column_name not in (select column_name from
information_schema.`COLUMNS` where table_name = @tableB)
);

/* get columns  in tableB which does not exist in tableA*/
set @extraColumnsB = (
    select GROUP_CONCAT(column_name) from information_schema.`COLUMNS`
        where table_name = @tableB
            and column_name not in (select column_name from
information_schema.`COLUMNS` where table_name = @tableA)
);

/* get the same column with the t1 alias for prefix to avoid ambiguous
column error */
set @sameColumns = (
    select GROUP_CONCAT(concat('t1.',column_name)) from
information_schema.`COLUMNS`
        where table_name = @tableA
            and column_name in (select column_name from
information_schema.`COLUMNS` where table_name = @tableB)
);

/* create the query in a variable*/
set @query =  concat('select ', @extraColumnsA, ', ', @extraColumnsB, ', ',
@sameColumns, ' from ', @tableA, ' as t1 inner join ', @tableB, ' as t2 on
t1.', @tableAJoinField , '= t2.' , @tableBJoinField);

/* create a prepared statement and execute it */
prepare stmt from @query;
execute stmt;
</code>

Αυτό που δεν ξέρω αν υπάρχει κάτι ανάλογο, γιατί είναι mysql extension,
είναι η GROUP_CONCAT() που κάνει concat τα rows ενος αποτελέσματος σε μία
γραμμή..

Πάντως ακόμα και αν τελικά κάνει τη δουλειά που θες, την κάνει με κακάσχημο
τροπο...

ΥΓ: για MySQL αφού πάρεις το result μετά το execution του statement τρέξε
και ένα "deallocate prepare stmt" να το καθαρίσεις.


2009/3/27 George Zarogiannis <zarogiannis at gmail.com>

> Μπορείς να φέρεις οποιαδήποτε πεδία θες, αλλά πρέπει να τα δηλώσεις ρητά,
> άσχετα αν έχουν κοινά ονόματα ή όχι.
> Δηλαδή πχ... SELECT A.a1, A.a2, B.b1, B.b2,.... FROM A INNER JOIN B ON
> A.Key = B.Key
>
> Το πρόβλημα είναι το: "όταν δεις ίδιο όνομα, φέρε μόνο του Α". Αυτό δε
> νομίζω ότι γίνεται με άλλο τρόπο εκτός από NATURAL JOIN, το οποίο όπως είπες
> προυποθέτει και ίδιες τιμές...
>
> 2009/3/27 Θοδωρής Λύτρας <thlytras at gmail.com>
>
> Παιδιά σωστά τα λέτε, κανονικά αυτό θα έπρεπε να μη παίζει στο σχήμα της
>> βάσης, ή τουλάχιστον τα όποια κοινά πεδία να έχουν και ίδιες τιμές, ώστε
>> να
>> αρκεί ένα NATURAL JOIN.
>>
>> Δυστυχώς οι πίνακες τους οποίους προσπαθώ να ενώσω είναι έτσι στραβά
>> φτιαγμένοι, και επειδή δεν είναι ένας και δύο προσπαθώ να φτιάξω μια
>> εφαρμογούλα για να τους συνενώνει σωστά. Και προσπαθούσα να βρω αν υπάρχει
>> κάποιος τρόπος να το κάνω αυτόματα, χωρίς να πρέπει να "διαβάσω" τα πεδία
>> και
>> των δύο πινάκων και να επιλέξω με το χέρι τα σωστά.
>>
>> Φαίνεται όμως οτι δεν υπάρχει τέτοια περίπτωση, απ' ότι μου λέτε... Πάντως
>> εντύπωση μου κάνει, γιατί το να υπάρχουν συνονόματα πεδία στους πίνακες
>> είναι
>> προφανώς ένα ρεαλιστικό σενάριο, και έχει προβλεφθεί (τουλάχιστον από την
>> sqlite, υποθέτω και από τις άλλες RDBMS). Βρίσκω περίεργο λοιπόν που δεν
>> υπάρχει κάποιο clause να ορίζει το αν θα πρέπει να κρατήσει και τα δύο
>> πεδία
>> ή μόνο το ένα.
>>
>> Θοδωρής
>>
>> Στις Παρ 27 Μαρ 2009, ο/η Tasos Laskos έγραψε:
>> > 8a symfoniso me ton George kai sta 2 point tou.
>> >
>> > Sostotero 8a itan to mono koino paidio sta 2 table na einai to id me to
>> > opoio ginete i antistixisi.
>> >
>> > George Zarogiannis wrote:
>> > > Νομίζω ότι όντως ζητάς πολλά από την SQL :)
>> > >
>> > > Ο μοναδικός τρόπος που μπορώ να σκεφτώ, υποθέτωντας ότι γράφεις σε
>> > > κάποια γλώσσα, είναι να διαβάσεις πρώτα τα πεδία των 2 πινάκων και
>> > > μετά να φτιάξεις δυναμικά το SELECT ώστε να περιέχει κάθε όνομα πεδίου
>> > > 1 φορά. Το πως θα το κάνεις αυτό, εξαρτάται από τη γλώσσα/βάση που
>> > > δουλεύεις...
>> > >
>> > > πχ ένας τρόπος να δεις τα πεδία ενός table από τη java, ανεξάρτητα
>> > > βάσης, είναι αυτός
>> > > <http://www.roseindia.net/jdbc/jdbc-mysql/ColumnName.shtml>
>> > >
>> > > Αλλά αυτό που θες μου φαίνεται λίγο περίεργο... μήπως πρέπει να
>> > > ξανασκεφτείς το σχήμα της βάσης;
>> > >
>> > > 2009/3/27 Theodore Lytras <thlytras at gmail.com
>> > > <mailto:thlytras at gmail.com>>
>> > >
>> > >     Έχω μια ερωτησούλα για όποιον ξέρει καλή SQL.
>> > >     Ψάχνω στον γκούγκλη αλλά άκρη δε βρίσκω....
>> > >
>> > >     Έστω οτι έχω δύο πίνακες A και B, με σχέση 1:1 και κοινό πεδίο
>> > > ονόματι id. Αν θέλω να συνενώσω τους δύο πίνακες, θα δώσω:
>> > >
>> > >     SELECT * FROM A, B WHERE A.id = B.id;
>> > >
>> > >     ή
>> > >
>> > >     SELECT * FROM A INNER JOIN B USING(id);
>> > >
>> > >     Το πρόβλημα τώρα προκύπτει στην περίπτωση που υπάρχουν πεδία στον
>> Α
>> > >     και στον Β με το ίδιο όνομα. Οι δύο προηγούμενες εντολές κρατούν
>> τα
>> > >     πεδία και των δύο πινάκων (αφού ορίζω SELECT * ), και (τουλάχιστο
>> σε
>> > >     SQLite που δοκίμασα) τα πεδία του δεύτερου πίνακα μετονομάζονται
>> με
>> > >     την προσθήκη ενός ":1" στο όνομά τους.
>> > >
>> > >     Υπάρχει κάποιος τρόπος να φιλτράρω τα πεδία του δεύτερου πίνακα?
>> Να
>> > >     του πω δηλαδή να επιλέξει όλα τα πεδία του πρώτου πίνακα, ΣΥΝ όλα
>> τα
>> > >     πεδία του δεύτερου που δεν υπάρχουν στον πρώτο πίνακα. Βεβαίως
>> αυτό
>> > > με κάποιο expression, χωρίς δηλαδή να ξέρω εκ των προτέρων τι πεδία
>> > > υπάρχουν στον ένα και στον άλλο πίνακα.
>> > >
>> > >     Υπ'όψιν οτι δε μιλώ για NATURAL JOIN, που (αν τουλάχιστον το
>> κατάλαβα
>> > >     σωστά) κρατά τις εγγραφές εκείνες εφόσον όλα τα "συνονόματα" πεδία
>> > >     έχουν ίδιες τιμές. Εγώ θέλω να του ορίζω σαφώς ένα κοινό πεδίο για
>> > >     INNER JOIN, και από τα υπόλοιπα "συνονόματα" πεδία να κρατά μόνο
>> τις
>> > >     τιμές που έχει ο ένας πίνακας, ανεξαρτήτως τι έχει ο άλλος
>> πίνακας.
>> > >
>> > >     Γίνεται αυτό? Ή ζητώ πολλά από την SQL????
>> > >
>> > >     Ευχαριστώ προκαταβολικά,
>> > >
>> > >     Θοδωρής
>>
>> --
>> linux-greek-users mailing list -- http://lists.hellug.gr
>>
>
>
>
> --
> linux-greek-users mailing list -- http://lists.hellug.gr
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.hellug.gr/pipermail/linux-greek-users/attachments/20090327/cf64da57/attachment.htm>


More information about the Linux-greek-users mailing list