MySQL: DISTINCT 2 rows...

Če se mi kdaj zaplete pri programiranju, pa je to pri kakšnem bolj zahtevnem MySQL stavku in zato vas prosim za pomoč.

Imam tabelo zasebna_sporocila, ki ima takšno strukturo:

id | fromuser | touser | message | date
1 | 1 | 3 | blablabla | 1043684100
2 | 1 | 2 | blablabla | 1049146320
3 | 2 | 1 | blablabla | 1049146920
4 | 3 | 1 | blablabla | 1049147100
5 | 2 | 3 | blablabla | 1049153340
6 | 1 | 2 | blablabla | 1049627280

Z navadnim DISTINCT ukazom (SELECT DISTINCT fromuser, touser FROM zasebna_sporocila) dobim takšen rezultat:

fromuser | touser
1 | 3
1 | 2
2 | 1
3 | 1
2 | 3

Problem pa je, ker bi rad dobil unikatne poizvedbe. V zgornjem rezultatu se prikaže 1 2 in 2 1 - kar bi želel, da se prikaže kot en rezultat, saj bi rad dobil zgrupirana sporočila med dvema uporabnikoma. Nekako podobno kot ima to narejeno Facebook v zasebnih sporočilih.

Nekam bi moral še dodati poizvedbo WHERE (fromuser = 1 OR touser = 1) - rezultat za uporabnika, ki ima id 1.

Seveda moram potem na koncu rezultate urediti po datumu (ORDER BY date DESC).

Kakršnakoli pomoč več kot dobrodošla! Zakomplicirano? :)

19 odgovorov

@blackmamba tudi o tem sem že razmišljal, ampak v tvojem primeru bi moral nekam še vstavit user id spremljivko, ki je vezana na določenega člana.

@Vini:

Poizvedba je potem enostavna:
SELECT
      zasebna_sporocila.*
   FROM
      zasebna_sporocila_pomozna,
      zasebna_sporocila
   WHERE
      zasebna_sporocila_pomozna.user_id = 1 AND
      zasebna_sporocila.id = zasebna_sporocila_pomozna.sporocilo_id
   ORDER BY
      zasebna_sporocila_pomozna.datum;

Tvoja koda potem vrne rezultate v tabeli, ki so vezane na uporabnika z recimo ID št. 1. Ampak s tem še ne dobim groupiranih / unikatnih poizvedb.

Primer:
dva uporabnika, eden z ID 1 in drug z ID 2, se med sabo dopisujete. Potem si dopusujeta še uporabnika z ID 1 in ID 3. In pa recimo up. ID 2 z up. ID 3.

Ker sem recimo jaz up. ID 1, želim dobite en rezultat id 1 & id 2, ter id 1 & id 3. Razmerje med ID 2 in ID 3 me pač ne "zanima", ker so pač zasebna sporočila.

Uf kako bi to bilo lažje obrazložiti v živo :)

Saj zdaj razmišljam, da je najlažje pogledati primer kar na FB strani:
https://www.facebook.com/messages/ (leva stran, kjer se nahajajo vsa sporočila med uporabniki)

Lucifix, imaš prav, seveda, moja napaka. Potrebuješ dve ID polji, v kateri zapišeš oba IDja v dva zapisa, enkrat fromuser v prvi ID, touser v drugi ID, v drugi zapis pa ravno obratno.

Način brez dodatne tabele. Vsi zadnji chati userja id=123, pogrupirani, sortirani po datumu.

V rezultatu "user1" je vedno userid=123, v "user2" je pa userid tistega s katerim je chatal.

Sporoči koliko časa se query izvaja in EXPLAIN.

SET @user_id = 123;

SELECT
IF(from_user = @user_id, from_user, to_user) AS user1,
IF(from_user = @user_id, to_user, from_user) AS user2,
`date`
FROM `zasebna_sporocila`
WHERE from_user=@user_id OR to_user=@user_id
GROUP BY user1, user2
ORDER BY `date` DESC;

EDIT: moja rešitev ni ravno hitra, če je veliko podatkov, dela pa.

Uporabi raje Vinijevo rešitev :)

Jao kaj so delali s strukturo tabel v sistemu phpBB2?!?! Ko nekdo dobi ZS, se ustvari nova vrstica samo za pošiljatelja - ala sent message. Groza za programiranje...

Hvala še 1x vsem za pomoč, ampak tokrat bom pa vrgel puško v koruzo in začel s čim bolj produktivnim :/

Ravno zadnjič sem nekaj podobnega delal. Torej PM sistem na podoben način kot ima FB. Nisem prebral vseh sporočil, vendar na kratko jaz bi dodal še eno polje thread_id.

Hmm nevem zakaj ne das index na from, to, in id.

In potem samo simple poizvedba

SELECT * FROM sporocila WHERE sporocila.to = 3 OR sporocila.from = 3 ORDER BY sporocila.id DESC

3 = id trenutno prijavlenega uporabnika.