Oprettet tir. d. 02. oktober 2012 kl. 09:34:26

ultraskytte
ultraskytte (1.430 point. Point ude: 0)

Sql problem vedr. join af to tabeller

Kære forum

Jeg er igang med at programmere nogle hjemmelavede fix til mit phpbb-forum, men jeg er stød tpå et database-problem, jeg har svært ved at løse. Håber, der er nogle kvikke/erfarne hoveder, der kan komme med et fornuftigt bud på, hvordan jeg kan løse problemet.

Min database indeholder følgende to tabeller (skåret ind til benet!):

mysql> explain database topics;

-----------+-----------------------+------+-----+---------+-------+
| Field    | Type                  | Null | Key | Default | Extra |
+-----------+-----------------------+------+-----+---------+-------+
| topic_id  | mediumint(8) unsigned | NO  | PRI | 0      |      |
+-----------+-----------------------+------+-----+---------+-------+

mysql> explain database topics_track;

+-----------+-----------------------+------+-----+---------+-------+
| Field    | Type                  | Null | Key | Default | Extra |
+-----------+-----------------------+------+-----+---------+-------+
| user_id  | mediumint(8) unsigned | NO  | PRI | 0      |      |
| topic_id  | mediumint(8) unsigned | NO  | PRI | 0      |      |
| mark_time | int(11) unsigned      | NO  |    | 0      |      |
+-----------+-----------------------+------+-----+---------+-------+

Table topics indeholder alle topics på forummet, og topics_track indeholder alle læste topics for brugerne, hvor mark_time angiver tidspunktet for læsningen. Har en bruger ikke læst en topic, figurer han dog ikke i tabellen.

Jeg ønsker at vise en liste, der indeholder både læste og ulæste topics for en specifik bruger med en status læst/ulæst tilknyttet hver topic.

Hvis jeg benytter følgende sql (fx for bruger med id 53):

SELECT T.topic_id, TT.mark_time FROM topics as T LEFT JOIN topics_track as TT ON TT.topic_id=T.topic_id WHERE TT.user_id=53 order by T.topic_id;

så vil jeg ikke få de topics med, som brugeren ikke har læst endnu, da disse ikke figurer i topics_track. Hvis jeg på en eller anden måde kunne få dem med, men hvor mark_time fx havde værdien NULL på de topics, der ikke var læste, så ville jeg have noget brugbart. Har dog lidt svært ved at lure, hvordan det lige kan lade sig gøre.

Håber, der er nogen, der kan komme med et fornuftigt bud!

mvh.

Thomas

Skrevet tir. d. 02. oktober 2012 kl. 11:40:35| #1

Christian_Belgien
Christian_Belgien (50.878 point)
Jeg vil foreslå en UNION query, hvor du først søger efter de topic_ids læst af bruger 53, og derefter søger efter de topics der ikke i topic_tracs har en bruger_id 53.  Såsom (ikke testet):

SELECT T.topic_id, TT.mark_time, 'laest'
FROM topics T
JOIN topics_track TT ON TT.topic_id = T.topic_id
WHERE TT.user_id = 53
UNION
SELECT topic_id, '', 'ulaest'
FROM topics
WHERE topic_id NOT IN(SELECT topic_id FROM topic_track WHERE user_id = 53)
ORDER BY topic_id

Skrevet tir. d. 02. oktober 2012 kl. 12:33:34| #2

ultraskytte
ultraskytte (1.430 point)
Tak for buddet, Christian. Har selv overvejet UNION. Det skal dog nævnes, at listen bliver genereret globalt under forummet, så sql'en skulle gerne være nogenlunde hurtig, hvis databasen skal kunne holde til den. Brug af både UNION og IN er temmelig hårde kald for databasen (specielt sidstnævne). Jeg var mere på udkig efter en god JOIN løsning, hvor man kunne få alle topics med i table topics også selvom der ikke var en tilsvarende værdi i table topics_track - og i disse tilfælde få en NULL-værdi el.lign. ud som mark_time. Er slet ikke klar over, om problemet kan løses. I så fald skal jeg gerne give point for dit svar :-)

Skrevet tir. d. 02. oktober 2012 kl. 20:41:45| #3

Christian_Belgien
Christian_Belgien (50.878 point)
Om det kan løses uden UNION ved jeg ikke (jeg ventede med dette svar for at se, om andre i mellemtiden havde en løsning).  Jeg eksperimenterede med IF, men fandt ikke noget der virkede.  Jeg opretter svar, som du bad om.

Skrevet ons. d. 03. oktober 2012 kl. 03:54:40| #4

arne_v
arne_v (1.048.773 point)
proev:

SELECT t.topic_id, tt.mark_time
FROM topics as t LEFT JOIN topics_track as tt ON tt.topic_id=t.topic_id
WHERE (tt.user_id=53 OR tt.user_id IS NULL) order by T.topic_id;

Skrevet ons. d. 03. oktober 2012 kl. 09:03:42| #5

ultraskytte
ultraskytte (1.430 point)
Tak for buddet, Arne. Sql'en virker dog ikke, men crasher databasen. Table topics_track er selvfølgelig meget stor, og ved at benytte "user_id IS NULL"
medtages alle resultater på samtlige user_id, der endnu ikke forekommer i topics_track - samt resultater på user_id 53. Det er en meget stor mængde data!

Skrevet søn. d. 07. oktober 2012 kl. 09:37:01| #6

ultraskytte
ultraskytte (1.430 point)
Er du vitterlig ikke nogen, der kan løse denne sql udfordring? Det er jo en relativ generel problematik indenfor anvendelse af sql JOINs:

Der skal uddrages alle poster fra tabel A med en tilhørende værdi V fra tabel B, hvor de to tabeller har en id relation. Hos de poster fra A uden sammenfald med B skal returneres NULL i stedet for V.

Det må da være en typisk problemstilling rigtig mange før mig er stødt på?

Ingen bud?

Skrevet søn. d. 07. oktober 2012 kl. 15:59:59| #7

arne_v
arne_v (1.048.773 point)
Det er et kendt problem med en kendt loesning:

mysql> CREATE TABLE topics_track (
    ->    user_id INTEGER NOT NULL,
    ->    topic_id INTEGER NOT NULL,
    ->    mark_time VARCHAR(50),
    ->    PRIMARY KEY (user_id,topic_id)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> INSERT INTO topics VALUES(1);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO topics VALUES(2);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO topics VALUES(3);
Query OK, 1 row affected (0.00 sec)

mysql>
mysql> INSERT INTO topics_track VALUES(52, 1, 'Mandag');
Query OK, 1 row affected (0.02 sec)

mysql> INSERT INTO topics_track VALUES(52, 2, 'Tirsdag');
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO topics_track VALUES(53, 1, 'Onsdag');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO topics_track VALUES(53, 2, 'Torsdag');
Query OK, 1 row affected (0.00 sec)

mysql>
mysql> SELECT * FROM topics;
+----------+
| topic_id |
+----------+
|        1 |
|        2 |
|        3 |
+----------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM topics_track;
+---------+----------+-----------+
| user_id | topic_id | mark_time |
+---------+----------+-----------+
|      52 |        1 | Mandag    |
|      52 |        2 | Tirsdag  |
|      53 |        1 | Onsdag    |
|      53 |        2 | Torsdag  |
+---------+----------+-----------+
4 rows in set (0.00 sec)

mysql>
mysql> SELECT t.topic_id, tt.mark_time
    -> FROM topics t JOIN topics_track tt ON t.topic_id=tt.topic_id
    -> ORDER BY t.topic_id;
+----------+-----------+
| topic_id | mark_time |
+----------+-----------+
|        1 | Mandag    |
|        1 | Onsdag    |
|        2 | Torsdag  |
|        2 | Tirsdag  |
+----------+-----------+
4 rows in set (0.00 sec)

mysql>
mysql> SELECT t.topic_id, tt.mark_time
    -> FROM topics t JOIN topics_track tt ON t.topic_id=tt.topic_id
    -> WHERE tt.user_id=53
    -> ORDER BY t.topic_id;
+----------+-----------+
| topic_id | mark_time |
+----------+-----------+
|        1 | Onsdag    |
|        2 | Torsdag  |
+----------+-----------+
2 rows in set (0.01 sec)

mysql>
mysql> SELECT t.topic_id, tt.mark_time
    -> FROM topics t LEFT JOIN topics_track tt ON t.topic_id=tt.topic_id
    -> ORDER BY t.topic_id;
+----------+-----------+
| topic_id | mark_time |
+----------+-----------+
|        1 | Mandag    |
|        1 | Onsdag    |
|        2 | Torsdag  |
|        2 | Tirsdag  |
|        3 | NULL      |
+----------+-----------+
5 rows in set (0.00 sec)

mysql>
mysql> SELECT t.topic_id, tt.mark_time
    -> FROM topics t LEFT JOIN topics_track tt ON t.topic_id=tt.topic_id
    -> WHERE tt.user_id=53 ORDER BY t.topic_id;
+----------+-----------+
| topic_id | mark_time |
+----------+-----------+
|        1 | Onsdag    |
|        2 | Torsdag  |
+----------+-----------+
2 rows in set (0.00 sec)

mysql>
mysql> SELECT t.topic_id, tt.mark_time
    -> FROM topics t LEFT JOIN topics_track tt ON t.topic_id=tt.topic_id
    -> WHERE (tt.user_id=53 OR tt.user_id IS NULL)
    -> ORDER BY t.topic_id;
+----------+-----------+
| topic_id | mark_time |
+----------+-----------+
|        1 | Onsdag    |
|        2 | Torsdag  |
|        3 | NULL      |
+----------+-----------+
3 rows in set (0.00 sec)

mysql>
mysql> DROP TABLE topics;
Query OK, 0 rows affected (0.00 sec)

mysql> DROP TABLE topics_track;
Query OK, 0 rows affected (0.00 sec)

Skrevet søn. d. 07. oktober 2012 kl. 16:02:57| #8

arne_v
arne_v (1.048.773 point)
Hvis du vil have flere raekker retur end din database og/eller app kan klare, saa har du et problem. Men det problem kan vi ikke loese.

Skrevet tor. d. 11. oktober 2012 kl. 19:07:21| #9

ultraskytte
ultraskytte (1.430 point)
Hej Arne

Jeg tror ikke, vi kommer videre. Men jeg synes, du er den, der kommer tættest på et svar, så hvis du vil åbne op for en pointgivning for sidste svar, så godkender jeg det.

mvh.

Thomas

Skrevet tor. d. 11. oktober 2012 kl. 19:35:52| #10


Skriv et indlæg




Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] [img]link til billede[/img]
Web- og emailadresser omdannes automatisk til links

Log ind

   


Seneste spørgsmål

Hjælp til at hente 5 poster og fremhæve den enkelte post...

Oprettet den 20. maj 2013 kl. 15.44
allandk giver 60 point for svar | Giv et svar »

fejl i while (gentager sekvens)

Oprettet den 19. maj 2013 kl. 10.58
magnus_rievers giver 30 point for svar | Giv et svar »

Select og 2 count

Oprettet den 17. maj 2013 kl. 17.15
steen-h giver 100 point for svar | Giv et svar »








Tips & Tricks fra PC World

Teaser billede

Her gemmer de hemmelige kopier af dine data sig

Hvad sker der, hvis din Mac bryder sammen og du ikke har taget backup? Fortvivl ikke. Der er gode chancer for, at der rundt omkring alligevel ligger sikkerhedskopier af dine data.


Anmeldelser fra PC World

Teaser billede

Test: Samsung Galaxy S4 er et hit - trods gøglertricks

Kan Samsung beholde førertrøjen i det store Android-race? Galaxy S4 er smækfyldt med innovative funktioner, men også med en del gøgl. Er det for meget? Få vores dom over Samsungs nye topmodel.


Seneste blogindlæg

Teaser billede

Tvangslukke spørgsmål: Hvad er den bedste løsning?

Hej Vi har mange åbne spørgsmål på Eksperten. Vi ville gerne tvangslukke dem - så et spørgsmål efter f.eks. 6 måneder lukkes. Men der er et par uklarheder som ville være gode at få lidt input til:...


Nyheder fra PC World

Teaser billede

Ny opfindelse: Oplad din mobil på 20 sekunder

Måske er det snart slut med at lade mobilen op hver aften. Med ny opfindelse kan telefonen få fuld energi på sølle 20 sekunder.


Nyheder fra Computerworld

Teaser billede

Snart kan du printe din egen pizza

Inden længe kan det blive muligt at printe pizzaer og andre fødevarer.


IT Kurser
Samarbejdspartnere

Udgiver · © 2013 IDG Danmark A/S · Hørkær 18 · 2730 Herlev · Tlf.: 77 300 300 · Fax: 77 300 301 · Brug af personoplysninger