Domanda

In this fiddle I have a single table called "tags". It has four columns:

id  counter sessionid  tag

(1, 1,     'session1', 'start'),
(2, 2,     'session1', 'sessionname1'),
(3, 3,     'session1', 'unimportant tag'),
(4, 4,     'session1', 'unimportant tag'),
(5, 5,     'session1', 'end'),
(6, 1,     'session2', 'start'),
(7, 2,     'session2', 'sessionname2'),
(8, 3,     'session2', 'end')

I want to display ALL columns of this table PLUS a additional row called "name". The data in this column is generated from the following conditions:

The name is written in the second row of each sessionid. This means in fact that I check which row has the tag "start". Then the name of the session is written in the column tag where counter is 1 higher than the row with tag = "start".

I tried a first query which works for the first sessionid, but then fails at second sessionid because it writes "sessionname1" in every row. The correct query would return name = "sessionname2" for the rows with id 6,7,8.

SELECT  t1.*,
    (SELECT top 1 t2.tag
     FROM tags t2
     JOIN ( SELECT * FROM tags WHERE tag = 'start' ) t3
       ON (t2.counter = t3.counter + 1) AND t3.sessionid = t2.sessionid
    ) AS name
FROM tags t1

What do I have to change to get the correct name in each row?

Checkout my SQL Fiddle

UPDATE

The expected output of course shows ALL rows. It would look like the following:

    id  counter sessionid  tag           name

(1, 1,     'session1', 'start',          'sessionname1'),
(2, 2,     'session1', 'sessionname1',   'sessionname1'),
(3, 3,     'session1', 'unimportant tag','sessionname1'),
(4, 4,     'session1', 'unimportant tag','sessionname1'),
(5, 5,     'session1', 'end',            'sessionname1'),
(6, 1,     'session2', 'start',          'sessionname2'),
(7, 2,     'session2', 'sessionname2',   'sessionname2'),
(8, 3,     'session2', 'end',            'sessionname2')

IMPORTANT NOTE:

It's important that the trackingcounter column is 1 bigger than the row with "start". It is NOT every time 2, there is also the possibility that the row with "start" has trackingcounter = 80 and then trackingcounter would have to be 81.

È stato utile?

Soluzione

Something like the following should work for you:

SELECT tags.*, tagnames.tag AS sessionname
FROM tags
INNER JOIN 
  (SELECT sessionid, tag 
   FROM tags WHERE counter = 2) AS tagnames 
ON tags.sessionid = tagnames.sessionid

This method works by creating a table that consists only of the session identifier and the name (this is the INNER JOIN subquery) which we then join back on to the main set to allow us to bring in the session name as a distinct column.

It makes two assumptions:

  1. The INNER JOIN specifies that we always expect there to be a name for our session
  2. The name tag will always be identified with a session id having counter = 2

EDIT:

From your comment, I see we cannot identify the name row by having counter = 2 BUT it will always be the second row for a given sessionid. Therefore, we can do the following to pick out the 2nd row per sessionid:

SELECT @previous_session := null;

         SELECT
          sessionid, 
          counter,
          tag,
          @counter_rank := IF(@previous_session = sessionid, @counter_rank + 1, 1) AS counter_rank,
          @previous_session := sessionid
          FROM tags
          ORDER BY sessionid, counter ASC

This generates an "artifical" row number using a user defined variable per session group so we can always locate the second record sorted by sessionid and counter.

Incorporating this into the first query gives us:

SELECT @previous_session := null;
SELECT tags.*, tagnames.tag AS sessionname
FROM tags
INNER JOIN 
  (SELECT countranks.sessionid, countranks.tag 
   FROM (
         SELECT
          sessionid, 
          counter,
          tag,
          @counter_rank := IF(@previous_session = sessionid, @counter_rank + 1, 1) AS counter_rank,
          @previous_session := sessionid
          FROM tags
          ORDER BY sessionid, counter ASC
   ) AS countranks WHERE countranks.counter_rank = 2

  ) AS tagnames 
ON tags.sessionid = tagnames.sessionid;

Here's the sql in action

Altri suggerimenti

You can try:

SELECT tags.id, tags.counter, tags.sessionid, tags.tag, t.name
FROM (tags
LEFT JOIN
  (SELECT sessionid, tag as name
   FROM tags
   WHERE counter = 2) as t
ON tags.sessionid = t.sessionid
) ;

Looks fine tested on this fiddle

Try this:

select b.*, (select tag from tags a where a.counter = 2 and a.sessionid = b.sessionid)  'NAME'
from tags b
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top