操纵复杂数据

时间:2015-06-01 18:14:32

标签: excel ms-access

我想制作一个以这种格式呈现/分析我的数据的表格:
             按月的价值

ID     Jan 09  Feb 09  Mar 09  Apr 09  May 09  Jun 09 Jul 09
1234   10      0       0       0       5       10       8 
2345   0       0       0       0       7        0       5
3456   5       0       0       7       0        0       3

我已经按照以下格式获得了数据(第一列中的月份,然后是第二列中的值),其中缺少的任何月份为“0”。如何在MS Access或Excel中操作它?

ID
1234  01-01-2009 10    01-06-2009 20    01-07-2009 15
2345  01-02-2009 15    01-04-2009 20    01-06-2009 10    01-07-2009 16
3456  01-03-2009 8     01-04-2009 30    01-07-2009 4

数据按月运行六年,因此手动操作非常复杂。

1 个答案:

答案 0 :(得分:1)

这是我提出的解决方案,如果您可以使用SQL,则使用SQL。我通常使用MS SQL Server 2008R2,因此我将在此答案中使用的查询将在那里工作,而我不能保证它在不同的SQL引擎上工作。

首先,我创建了表并使用您在问题中的数据,我有:

enter image description here

这里我们有一个名为“#' SO'的数据库,其中有一个名为' dbo.Test'以及描述的列和数据类型。 nvarchar(10)表示列包含最大长度为10的基于文本的值。结尾处的null表示列中也可以有空值(类似于空值)。

所以我所做的不是问题就是提供一些标题,第一列是' ID'以及随后的所有交替的' DaX'和' VaX' (X表示一个数字,而“Da”表示日期,“Va”表示数值')。请注意,将值导入为数字实际上更好(我忘了将它们导入为此并决定保留它,以表明即使这样也可以。)

所以下面的查询是非常先进的(至少在我看来),因为它从变量构建了一个查询,我自己必须看一下才能使语法正确并且代码正常工作。要运行它,您需要创建一个新查询,粘贴下面的代码并执行代码。

-- Use the database named SO
USE SO

-- Create some variables
DECLARE @Script  VARCHAR(MAX), -- The variable to hold the final script
        @Dates   VARCHAR(MAX), -- This will hold the column names of date columns
        @Values  VARCHAR(MAX)  -- This will hold the column names of value columns      

-- This is a temporary table holding the column number and column
-- names for date columns.
;WITH [Cols] AS (
    -- Get column number and column names from sys.table
    SELECT
        ROW_NUMBER() OVER(ORDER BY name) AS [RowID],
        [name]
    FROM
        sys.columns
    -- Where the object is the data table called Test
    WHERE
        [object_id] = object_id('Test')
    -- And where the column name begins with 'da' (case insensitive)
    AND
        [name] LIKE 'da%'
),
-- Another temporary table that uses the above to make a comma 
-- separated list of all date column names. It uses recursion to do that
[Concted] AS (
    -- Get the first column number and name from the above temp table
    SELECT
        [RowID],
        CAST([name] AS VARCHAR(MAX)) AS [name]
    FROM
        [Cols]
    WHERE
        [RowID] = 1
    -- Add it to...
    UNION ALL
    -- The current column name, a comma and another column name
    SELECT
        [Cols].[RowID],
        CAST([Concted].[name] + ',' + [Cols].[name] AS VARCHAR(MAX))
    FROM
        [Concted]
    JOIN
        [Cols]
    -- That other column name determined by taking the current row number and the next
    ON
        [Cols].[RowID] = [Concted].[RowID] + 1
)
-- Get the first row from the second temp table (which now contains all
-- dates separated by comma and store in @Dates
SELECT 
    @Dates = [name]
FROM
    [Concted]
WHERE
    [RowID] = (SELECT MAX([RowID]) FROM Concted)


-- Do the same for values
;WITH [Cols] AS (
    SELECT
        ROW_NUMBER() OVER(ORDER BY name) AS [RowID],
        [name]
    FROM
        sys.columns
    WHERE
        [object_id] = object_id('Test')
    AND
        [name] LIKE 'va%'
),
[Concted] AS (
    SELECT
        [RowID],
        CAST([name] AS VARCHAR(MAX)) AS [name]
    FROM
        [Cols]
    WHERE
        [RowID] = 1
    UNION ALL
    SELECT
        [Cols].[RowID],
        CAST([Concted].[name] + ',' + [Cols].[name] AS VARCHAR(MAX))
    FROM
        [Concted]
    JOIN
        [Cols]
    ON
        [Cols].[RowID] = [Concted].[RowID] + 1
)
SELECT 
    @Values = [name]
FROM
    [Concted]
WHERE
    [RowID] = (SELECT MAX([RowID]) FROM Concted)


-- Here we build the 'skeleton' of the main script, and it uses the two 
-- lists of columns we built earlier above.
SET @Script = '
    -- Select the ID, dates and values
    SELECT
        [ID],
        [Dates],
        [Values]
    FROM
        Test
    -- Unpivot once on dates
    UNPIVOT (
        [Dates] FOR [Date] IN ('+@Dates+')
    ) AS u1
    -- Unpivot a second one for values
    UNPIVOT (
        [Values] FOR [Value] IN ('+@Values+')
    ) AS u2
    -- Where the column number for date and value match and 
    -- neither dates nor values are blanks
    WHERE
        SUBSTRING([Date],3,LEN([Date])) = SUBSTRING([Value],3,LEN([Value]))
    AND
        ISNULL([Dates],'''') <> ''''
    AND
        ISNULL([Values],'''') <> ''''
'
-- Execute the above script
EXEC (@Script)

我在代码中尽可能多地解释了注释(以--开头的行)。一旦运行,我从上面得到以下内容:

ID      Dates       Values
1234    01/01/2009  10
1234    01/06/2009  20
1234    01/07/2009  15
2345    01/02/2009  15
2345    01/04/2009  20
2345    01/06/2009  10
2345    01/07/2009  16
3456    01/03/2009  8
3456    01/04/2009  30
3456    01/07/2009  4

获得上表后,我们可以将其复制/粘贴到Excel中以运行数据透视表,只需点击几下,我们就可以获得:

enter image description here