2011-09-20 4 views
1

J'ai le tableau suivant.Zend DB Joindre 2 rangées de la même table

--------------------------------------------- 
check_id | action_id | user_id |   dt | 
--------------------------------------------- 
     1 |   1 |  6 | 2011-09-17 | 
     2 |   1 |  6 | 2011-09-18 | 
     3 |   3 |  6 | 2011-09-19 | 
     4 |   3 |  6 | 2011-09-20 | 
--------------------------------------------- 

Je voudrais interroger cette table et obtenir le résultat suivant.

----------------------------------------------- 
action_id | user_id | dt_start |  dt_end | 
----------------------------------------------- 
     1 |  6 | 2011-09-17 | 2011-09-18 | 
     3 |  6 | 2011-09-19 | 2011-09-20 | 
----------------------------------------------- 

Donc j'utilise la requête suivante.

$checks->select() 
->from(array('c1' => 'checks'), array('dt as dt_start') 
->joinLeft(array('c2' => 'checks'), 'c1.action_id = c2.action_id', array('dt as dt_end') 
->where('c1.user_id = ?', $userId) 
->group('c1.action_id') 

Mais cela me donne le résultat suivant.

----------------------------------------------- 
action_id | user_id | dt_start |  dt_end | 
----------------------------------------------- 
     1 |  1 | 2011-09-17 | 2011-09-17 | 
     1 |  3 | 2011-09-19 | 2011-09-19 | 
----------------------------------------------- 

Quelqu'un peut-il me dire ce que je fais mal?

+1

Ce que SQL que vous essayez de créer via Zend_Db_Select n'est pas immédiatement clair pour moi. Pouvez-vous ajouter le SQL à la question? En outre, vous pouvez utiliser la méthode Zend_Db_Select :: toString pour imprimer le SQL qui sera exécuté lors de la requête, ce qui peut vous aider à déboguer. –

Répondre

1

Essayez cette requête, sans le groupe par:

SELECT * 
FROM checks c1 LEFT OUTER JOIN checks c2 ON c1.action_id = c2.action_id 
WHERE c1.user_d = 6 

Vous verrez que vous obtenez les matchs où c1.dt < c2.dt, qui est ce que vous voulez. Mais vous obtenez également des correspondances où c1.dt> c2.dt, et où c1.dt = c2.dt. En d'autres termes, l'auto-jointure inclut les résultats où c1 et c2 pointent sur la même ligne.

Ensuite, vous utilisez un GROUP BY qui réduit plusieurs lignes en une, mais MySQL choisit une ligne arbitraire du groupe. (Ceci est une requête ambiguë, et si vous SET SQL_MODE='ONLY_FULL_GROUP_BY' vous obtiendrez une erreur.)

Ainsi, votre autojointure et GROUP BY seulement retours c1 et c2 qui sont en fait la même rangée.

Pour corriger cela, vous devez ajouter une condition que c1.dt < c2.dt.

$checks->select() 
->from(array('c1' => 'checks'), array('dt as dt_start') 
->joinLeft(array('c2' => 'checks'), 
      'c1.action_id = c2.action_id AND c1.dt < c2.dt', 
      array('dt as dt_end') 
->where('c1.user_id = ?', $userId) 

Vous ne avez probablement pas besoin du GROUP BY du tout dans ce cas, en supposant que vous n'avez pas plusieurs commence et se termine pour chaque action. Par ailleurs, ce type de complexité est l'une des raisons pour lesquelles il est généralement recommandé de stocker les données de début et de fin d'événement sur une seule ligne, le début dans une colonne et la fin dans une deuxième colonne.

+0

L'utilisation d'un GROUP BY id_action me donne les résultats dont j'ai besoin. Je pourrais aussi utiliser un joinRight mais cela me donne aussi des résultats avec une seule ligne. J'ai besoin de résultats lorsque deux lignes partagent le même action_id. Peut-être stocker la date de début et de fin dans une seule rangée est une meilleure solution. Je construis un système de check-in/check-out. – Stuiterbal

+0

Une jointure à droite ne renvoie pas la ligne où un ID d'action n'est pas encore partagé avec une autre ligne. J'ai besoin de ceux-là aussi. Donc, un LEFT JOIN combiné avec un GROUP BY fait l'affaire. – Stuiterbal

+0

Très bien, mais avez-vous eu la partie que j'ai couvert à propos de tester fot c1.dt

Questions connexes