SQL SELECT从具有特殊条件的同一表生成其他列

时间:2014-04-28 08:32:12

标签: mysql sql select inner-join conditional-statements

this fiddle中,我有一个名为“tags”的表。它有四列:

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')

我想显示此表的所有列 PLUS 一个名为“name”的附加行。 此列中的数据由以下条件生成:

该名称写在每个 sessionid的第二行。这实际上意味着我检查哪一行标记为“开始”。然后,会话名称将写入列标记,其中计数器高1 ,而不是带有tag =“start”的行。

我尝试了第一个查询,它适用于第一个 sessionid ,但后来在第二个sessionid失败,因为它在每一行写入“sessionname1”。对于ID为6,7,8的行,正确的查询将返回name =“sessionname2”。

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

为了在每一行中获得正确的名称,我需要更改什么?

结帐我的SQL Fiddle

更新

当然预期输出显示所有行。 它看起来如下:

    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')

重要提示:

跟踪计数器列比具有“start”的行强1 更重要。每次2 NOT ,“start”行也有可能跟踪计数器= 80,然后跟踪计数器必须为81.

3 个答案:

答案 0 :(得分:1)

以下内容适用于您:

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

此方法的工作原理是创建一个只包含会话标识符和名称(这是INNER JOIN子查询)的表,然后我们将其连接回主集,以允许我们将会话名称作为一个独特的引入列。

它有两个假设:

  1. INNER JOIN指定我们始终希望会话名称
  2. 将始终使用具有counter = 2
  3. 的会话ID标识名称标记

    修改

    从您的评论中,我发现我们无法通过counter = 2来识别名称行,但它始终是给定sessionid的second行。因此,我们可以执行以下操作来挑选每个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
    

    这会使用每个会话组user defined variable生成一个“人工”行号,这样我们就可以找到按sessionid和counter排序的第二条记录。

    将其纳入第一个查询会给我们:

    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;
    

    这是sql in action

答案 1 :(得分:0)

您可以尝试:

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
) ;

this fiddle

上看起来经过精心测试

答案 2 :(得分:0)

试试这个:

select b.*, (select tag from tags a where a.counter = 2 and a.sessionid = b.sessionid)  'NAME'
from tags b