基于sql条件将行转换为列

基于sql条件将行转换为列,sql,duplicates,transpose,Sql,Duplicates,Transpose,我有一个下表(一个简化的示例,事实上,该表包含多个ID,日期数可变,每个日期的事件数可变): 我试图得到一个表,其中我将有不同的ID/日期对,其中有多个事件被重新编码的行被转置到列中。因此,我正在寻找一个表,在本例中,该表如下所示: IDs Date Event Event2 Event3 102 1996-10-16 00:00:00 A NULL NULL 102 1996-10-23 00:00:00 A

我有一个下表(一个简化的示例,事实上,该表包含多个ID,日期数可变,每个日期的事件数可变):

我试图得到一个表,其中我将有不同的ID/日期对,其中有多个事件被重新编码的行被转置到列中。因此,我正在寻找一个表,在本例中,该表如下所示:

IDs   Date                  Event   Event2   Event3
102   1996-10-16 00:00:00   A       NULL     NULL
102   1996-10-23 00:00:00   A       B        NULL
102   1997-01-14 00:00:00   A       NULL     NULL
103   1997-01-14 00:00:00   D       NULL     NULL
103   1997-01-15 00:00:00   A       NULL     NULL
103   1997-01-16 00:00:00   A       B        C

很抱歉没有发布任何代码,但坦率地说,我甚至不知道如何从这开始。

如果您只有两个事件,您可以使用
min()
max()
,以及一些附加逻辑来执行此操作:

select ids, date, min(event) as event,
       (case when min(event) <> max(event) then max(event) end) as event2
from table t
group by ids, date;
选择ID、日期、分钟(事件)作为事件,
(最小(事件)最大(事件)然后最大(事件)结束时的情况)作为事件2
来自表t
按ID、日期分组;

这是标准SQL,因此它应该可以在任何数据库中工作。

如果您只有两个事件,则可以使用
min()
max()
和一些附加逻辑来执行此操作:

select ids, date, min(event) as event,
       (case when min(event) <> max(event) then max(event) end) as event2
from table t
group by ids, date;
选择ID、日期、分钟(事件)作为事件,
(最小(事件)最大(事件)然后最大(事件)结束时的情况)作为事件2
来自表t
按ID、日期分组;

这是标准的SQL,所以它应该可以在任何数据库中工作。

尝试此操作,首先选择id,然后根据上述id获取所有列

<?php
    $query = $database->getRows("SELECT DISTINCT ids FROM table");  
    ?>

    <table>
    <?php foreach($query as $row){ ?>
            <tr>

                <td><?php echo $row['ids']; ?></td>

            <?php
            $id= $row["ids"];
            $sub_inner = $database->getRows("SELECT date,Event,Event2 FROM table where ids= :ids",
            array(':ids'=>$id));                        
            ?>


    <td><?php foreach($sub_inner as $list){ ?><?php echo $list['date']; ?></td><td><?php echo $list['Event']; ?><?php } ?></td> 
    <td><?php echo $list['Event2']; ?></td> 

    <?php } ?>

首先尝试选择id,然后根据上述id获取所有列

<?php
    $query = $database->getRows("SELECT DISTINCT ids FROM table");  
    ?>

    <table>
    <?php foreach($query as $row){ ?>
            <tr>

                <td><?php echo $row['ids']; ?></td>

            <?php
            $id= $row["ids"];
            $sub_inner = $database->getRows("SELECT date,Event,Event2 FROM table where ids= :ids",
            array(':ids'=>$id));                        
            ?>


    <td><?php foreach($sub_inner as $list){ ?><?php echo $list['date']; ?></td><td><?php echo $list['Event']; ?><?php } ?></td> 
    <td><?php echo $list['Event2']; ?></td> 

    <?php } ?>

有关方法的详细信息

以及完整的答案:

请尝试以下代码:

-- Temporary table...
create table ##myTable (
        IDs int
        ,[Date] datetime
        ,[Event] varchar(1)
        )

-- ... with sample data
insert ##myTable
        select 102, '2010-01-01', 'A'
union   select 102, '2010-01-01', 'B'
union   select 102, '2010-01-01', 'C'
union   select 102, '2010-01-01', 'E'
union   select 103, '2010-01-01', 'A'
union   select 104, '2010-01-01', 'B'
union   select 104, '2010-01-01', 'C'
union   select 105, '2010-01-01', 'F'

-- Variables
DECLARE @cols   AS NVARCHAR(MAX)
        ,@query AS NVARCHAR(MAX)

-- Build column name for our result.
-- The ROW_NUMBER() operator gives us the rank of the event for
-- the combination of IDs and Date. With that, event B for IDs 104
-- will have rank 1, and then will appear in the 1st column.
SELECT  @cols = STUFF(
                       (SELECT  DISTINCT
                        ',' + QUOTENAME('Event' + LTRIM(STR(
                                    ROW_NUMBER() OVER (
                                        PARTITION BY IDs, [Date]
                                        ORDER BY IDs, [Date]
                                    )
                                )))
                        FROM    ##myTable
                        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
                    , 1, 1, '')

set @query = '
    SELECT  IDs, [Date], ' + @cols + '
    FROM    (
            SELECT  IDs
                    ,[Date]
                    ,[Event]
                    ,''Event'' + LTRIM(STR(
                            ROW_NUMBER() OVER (
                                PARTITION BY IDs, [Date]
                                ORDER BY IDs, [Date]
                            )
                    )) as [EventNo]
            FROM    ##myTable
            ) x
    PIVOT
            (
            MAX([Event])
            FOR [EventNo] IN (' + @cols + ')
            ) p'

execute sp_executesql @query

-- Remove temporary table
drop table ##myTable
结果是:

有关方法的详细信息

以及完整的答案:

请尝试以下代码:

-- Temporary table...
create table ##myTable (
        IDs int
        ,[Date] datetime
        ,[Event] varchar(1)
        )

-- ... with sample data
insert ##myTable
        select 102, '2010-01-01', 'A'
union   select 102, '2010-01-01', 'B'
union   select 102, '2010-01-01', 'C'
union   select 102, '2010-01-01', 'E'
union   select 103, '2010-01-01', 'A'
union   select 104, '2010-01-01', 'B'
union   select 104, '2010-01-01', 'C'
union   select 105, '2010-01-01', 'F'

-- Variables
DECLARE @cols   AS NVARCHAR(MAX)
        ,@query AS NVARCHAR(MAX)

-- Build column name for our result.
-- The ROW_NUMBER() operator gives us the rank of the event for
-- the combination of IDs and Date. With that, event B for IDs 104
-- will have rank 1, and then will appear in the 1st column.
SELECT  @cols = STUFF(
                       (SELECT  DISTINCT
                        ',' + QUOTENAME('Event' + LTRIM(STR(
                                    ROW_NUMBER() OVER (
                                        PARTITION BY IDs, [Date]
                                        ORDER BY IDs, [Date]
                                    )
                                )))
                        FROM    ##myTable
                        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
                    , 1, 1, '')

set @query = '
    SELECT  IDs, [Date], ' + @cols + '
    FROM    (
            SELECT  IDs
                    ,[Date]
                    ,[Event]
                    ,''Event'' + LTRIM(STR(
                            ROW_NUMBER() OVER (
                                PARTITION BY IDs, [Date]
                                ORDER BY IDs, [Date]
                            )
                    )) as [EventNo]
            FROM    ##myTable
            ) x
    PIVOT
            (
            MAX([Event])
            FOR [EventNo] IN (' + @cols + ')
            ) p'

execute sp_executesql @query

-- Remove temporary table
drop table ##myTable
结果是:


不幸的是,事件的数量会有很大的差异。大多数ID/日期只有1个,但可能有一些ID/日期对最多有10个事件。不幸的是,事件的数量差异很大。大多数ID/日期只有1个,但可能有一些ID/日期对最多有10个事件。谢谢您的建议。我承认这远远超出了我目前的sql知识水平。。。但我有一个问题。它为每个可能的事件生成一列。因此,如果我在整个数据集中有100个不同的事件,它将产生100列,而大多数动物只有几个条目。是否不可能有一个类似的表,而不是有一个特定的事件类型作为列,而是有“Event1”、“Event2”等?这将大大节省空间!嗯,也许你可以用其他例子来完善你的问题。您想在不同行的同一列“Event 1”中查看事件A和事件B(某种程度上将结果减少为有用的列),还是希望使用规范化的列名(或两者兼有)?我现在编辑了这个问题,希望它能更好地显示我所追求的。事件列的总数应为给定ID/日期对记录的最大事件数,而不是数据中重新编码的不同事件数。因此,在本例中,我记录了4个不同的事件,但同一个人在同一天只记录了3个,因此我要查找的列数是3。我根据您上次的精度更新了查询。这正是我要查找的!非常感谢。再问一两个问题。首先,列的顺序是随机的,即我得到Event14、Event2、Event10等。。。这是一个装饰性的东西,但我只是想检查一下,这不是一个问题的迹象?第二,我从未使用过这样的语法,我有点困惑,当我想保存表格时,我应该把“into”语句放在哪里……谢谢你的建议。我承认这远远超出了我目前的sql知识水平。。。但我有一个问题。它为每个可能的事件生成一列。因此,如果我在整个数据集中有100个不同的事件,它将产生100列,而大多数动物只有几个条目。是否不可能有一个类似的表,而不是有一个特定的事件类型作为列,而是有“Event1”、“Event2”等?这将大大节省空间!嗯,也许你可以用其他例子来完善你的问题。您想在不同行的同一列“Event 1”中查看事件A和事件B(某种程度上将结果减少为有用的列),还是希望使用规范化的列名(或两者兼有)?我现在编辑了这个问题,希望它能更好地显示我所追求的。事件列的总数应为给定ID/日期对记录的最大事件数,而不是数据中重新编码的不同事件数。因此,在本例中,我记录了4个不同的事件,但同一个人在同一天只记录了3个,因此我要查找的列数是3。我根据您上次的精度更新了查询。这正是我要查找的!非常感谢。再问一两个问题。首先,列的顺序是随机的,即我得到Event14、Event2、Event10等。。。这是一个装饰性的东西,但我只是想检查一下,这不是一个问题的迹象?第二,我从未使用过这样的语法,我有点困惑,当我想保存表时,应该把“into”语句放在哪里。。。