【问题标题】:Dynamic Pivot -- Show Fields Only if Needed动态透视——仅在需要时显示字段
【发布时间】:2017-11-21 16:52:21
【问题描述】:

我在 VB 中运行一个小脚本,我试图只显示 startDate 和 endDate 之间的月份。这是我的VB+SQL。我认为这是 SQL 问题,而不是 VB 问题。

Private Sub ChartData_Click(sender As Object, e As EventArgs) Handles ChartData.Click


    'Initialize the objects before use
    Dim dataAdapter As New SqlClient.SqlDataAdapter()
    Dim dataSet As New DataSet
    Dim command As New SqlClient.SqlCommand
    Dim datatableMain As New System.Data.DataTable()
    Dim connection As New SqlClient.SqlConnection
    Dim DestName As String
    Dim VBstartDate As Date
    Dim VBendDate As Date
    Dim strSql As String

    MessageBox.Show("Please notice: it may take 1-2 minutes to product your report, depending on the volume of data selected!")

    'Assign your connection string to connection object
    connection.ConnectionString = "Data Source=Server-Name;Initial Catalog=DB-Name;Integrated Security=True"
    command.Connection = connection
    command.CommandType = CommandType.Text
    'You can use any command select

    VBstartDate = DatePickerStart.Value.ToString("MM/dd/yyyy")
    VBendDate = DatePickerEnd.Value.ToString("MM/dd/yyyy")

    strSql = "SELECT * FROM (SELECT Contact_ID, TB_Line, Deal_Balance, DATENAME(Month,[AsOfDate]) AS TheDate FROM [TBL_Deposit_HIST] Where [AsOfDate] >= '" & VBstartDate & "' and [AsOfDate] <= '" & VBendDate & "') AS P PIVOT (SUM(DEAL_BALANCE) FOR TheDate in (January, February, March, April, May, June, July, August, September, October, November, December)) AS PV;"
    command.CommandText = StrSql
    dataAdapter.SelectCommand = command

    'Dim f As FolderBrowserDialog = New FolderBrowserDialog
    Try
        'If f.ShowDialog() = DialogResult.OK Then
        'This section help you if your language is not English.
        System.Threading.Thread.CurrentThread.CurrentCulture =
            System.Globalization.CultureInfo.CreateSpecificCulture("en-US")
        Dim oExcel As Excel.Application
        Dim oBook As Excel.Workbook
        Dim oSheet As Excel.Worksheet
        Dim oRange As Excel.Range

        oExcel = CreateObject("Excel.Application")
        oBook = oExcel.Workbooks.Add(Type.Missing)
        oSheet = oBook.Worksheets(1)
        'oRange = oExcel.Range

        Dim columnLetter As String
        Dim dc As System.Data.DataColumn
        Dim dr As System.Data.DataRow
        Dim colIndex As Integer = 0
        Dim rowIndex As Integer = 0

        'Fill data to datatable
        connection.Open()
            dataAdapter.Fill(datatableMain)
            connection.Close()


            'Export the Columns to excel file
            For Each dc In datatableMain.Columns
                colIndex = colIndex + 1
                oSheet.Cells(1, colIndex) = dc.ColumnName
            Next

            'Export the rows to excel file
            For Each dr In datatableMain.Rows
                rowIndex = rowIndex + 1
                colIndex = 0
                For Each dc In datatableMain.Columns
                    colIndex = colIndex + 1
                    oSheet.Cells(rowIndex + 1, colIndex) = dr(dc.ColumnName)
                Next
            Next

        Dim LastRow As Long
        Dim LastColumn As Long
        Dim StrLastCol As String

        ' Find last row and last column
        With oSheet
            LastRow = .Cells(.Rows.Count, 1).End(Excel.XlDirection.xlUp).Row
            LastColumn = .Cells(1, .Columns.Count).End(Excel.XlDirection.xlToLeft).Column
        End With

        ' Convert column number to column letter
        Select Case LastColumn
            Case 1 To 26
                StrLastCol = Convert.ToChar(Convert.ToInt32("A"c) + LastColumn - 1).ToString()
            Case 27 To 52
                StrLastCol = Convert.ToChar(Convert.ToInt32("a"c) + LastColumn - 27).ToString()
            Case Else
                StrLastCol = String.Empty
        End Select

        'create chart object
        Dim chartPage As Excel.Chart
        Dim xlCharts As Excel.ChartObjects
        Dim myChart As Excel.ChartObject
        Dim chartRange As Excel.Range

        xlCharts = oSheet.ChartObjects
        myChart = xlCharts.Add(10, 80, 300, 250)
        chartPage = myChart.Chart

        ' Set dynamic range
        chartRange = oSheet.Range("A1:" & StrLastCol & "25")
        chartPage.SetSourceData(Source:=chartRange)
        chartPage.ChartType = Excel.XlChartType.xlColumnClustered

        'Set final path for saving Excel Report
        DestName = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) & "\Report.xls"

        oExcel.Visible = True
        oSheet.Columns.AutoFit()
        'Save file in final path
        oBook.SaveAs(DestName, XlFileFormat.xlWorkbookNormal, Type.Missing,
            Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlExclusive,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing)


        'Release the objects
        ReleaseObject(oSheet)
            oBook.Close(False, Type.Missing, Type.Missing)
            ReleaseObject(oBook)
            oExcel.Quit()
            ReleaseObject(oExcel)
            'Some time Office application does not quit after automation: 
            'so i am calling GC.Collect method.
            GC.Collect()

        MessageBox.Show("Export done successfully! You can find your report on your desktop!!")

        'End If
    Catch ex As Exception
        MessageBox.Show(ex.Message, "Warning", MessageBoxButtons.OK)
    End Try

End Sub

例如,这似乎很接近。

DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX);
declare @startDate datetime
declare @endDate datetime        
set @startDate = '10/10/2017'
set @endDate = '11/30/2017'
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.AsOfDate) 
            FROM [TBL_Deposit_HIST] c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT Contact_ID, ' + @cols + ' from 
            (
                SELECT Contact_ID,  
                Deal_Balance,
                AsOfDate
                from [TBL_Deposit_HIST]
           ) x
            pivot 
            (
                 SUM(Deal_Balance)
                WHERE AsOfDate BETWEEN (' + @cols + ') AND (' + @cols + ') 
            ) p '
execute(@query)

但是,这给了我以下错误。

Msg 156, Level 15, State 1, Line 11
Incorrect syntax near the keyword 'WHERE'.

下面的脚本确实可以编译,但它给我的日期范围太宽了。

DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX);
declare @startDate datetime
declare @endDate datetime        
set @startDate = '10/10/2017'
set @endDate = '11/30/2017'
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.AsOfDate) 
            FROM [TBL_Deposit_HIST] c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT Contact_ID, ' + @cols + ' from 
            (
                SELECT Contact_ID,  
                Deal_Balance,
                AsOfDate
                from [TBL_Deposit_HIST]
           ) x
            pivot 
            (
                 SUM(Deal_Balance)
                for AsOfDate in (' + @cols + ')

            ) p '
execute(@query)

我想我需要一个 Where 和 Between,但我无法让它正常工作。

结果显示在 Excel 中。 DatePicker 工作正常,SQL 确实按照我的要求执行,但它显示一年的所有月份,即使我选择,假设 17 年 9 月 1 日到 2017 年 11 月 20 日。有没有办法让数据透视字段与动态日期一起动态。还是我必须按原样运行它,并删除 Excel 中第 2 行为空的任何列,或者类似的东西?我只想显示 startDate 和 endDate 之间的数据。谢谢。

【问题讨论】:

    标签: sql sql-server vb.net


    【解决方案1】:

    如果要显示两个日期之间的月份,则应确保包括年份,因为您可能会遇到日期从 25 Nov 201715 Mar 2018 的情况。

    我设计了一个示例数据,将月份显示为[yyyy-MMM]

    说明

    1. @start@end 之间的所有月份构建列,您可以通过使用where 子句将查询应用于您的表只查找使用的确切月份来跳过此操作。
    2. 从您的表格中获取所有数据,并将日期格式化为[yyyy-MMM],为此我使用了report cte
    3. 应用枢轴

    查询

    if exists( select 1 from #data)
         drop table #data
    create  table #data(
       Id int not null identity(1,1),
       AsOfDate datetime,
       Balance money
    )
    
    insert into #data(AsOfDate,Balance)
    values ('11 Oct 2017',1854.24),
           ('15 Sep 2017',1554.25),
           ('11 Sep 2017',1554.14),
           ('09 May 2017',255.55),
           ('27 Sep 2017',145.15)
    
      declare @start datetime = '05 May 2017',
              @end datetime ='17 Sep 2017'
    
     declare @cols varchar(max),
             @query varchar(max);
    
    with months as(
        select @start as [Date], quotename(format(@start,'yyyy MMM')) as [Month]
        union all
        select dateadd(month,1,[Date]),quotename(format(dateadd(month,1,[Date]),'yyyy MMM'))
        from months
        where [Date] < @end
    )
    
     select @cols = stuff((select ',' + [Month]
                       from months
                       order by [Date]
                       for xml path(''),type).value('.','nvarchar(max)'),1,1,'')
    
    
     select @query = ';with report as(
                    select sum(Balance) [Balance],format(AsOfDate,''yyyy MMM'') as [Date]
                    from #data
                    where AsOfDate between ''' + cast(@start as varchar) + ''' and ''' + cast( @end as varchar) + '''
                    group by format(AsOfDate,''yyyy MMM''))
                select ' + @cols + '
                from report 
                pivot(sum(Balance) for [Date] in('+ @cols +')) p'
    
    exec (@query)    
    

    输出结果

    2017 May    2017 Jun    2017 Jul    2017 Aug    2017 Sep    2017 Oct
    255.55  NULL    NULL    NULL    3108.39 NULL
    

    希望对你有帮助

    【讨论】:

      【解决方案2】:

      是否在 select 中包含 WHERE 子句:

      SELECT Contact_ID,  
                      Deal_Balance,
                      AsOfDate
      from [TBL_Deposit_HIST]
      WHERE AsOfDate BETWEEN (' + @cols + ') AND (' + @cols + ') 
      

      ...不工作?

      【讨论】:

      • 我在发帖前试过了。我虽然这样可行,但我明白了:关键字'WHERE'附近的语法不正确。
      • 谢谢莫娜。似乎这可能是解决方案。你能帮我调整你的代码以适应我的具体情况吗?我尝试了几件事,但无法正常工作。谢谢。
      猜你喜欢
      • 1970-01-01
      • 2021-10-12
      • 2012-08-10
      • 1970-01-01
      • 2013-03-18
      • 2015-09-17
      • 1970-01-01
      • 2013-06-14
      • 1970-01-01
      相关资源
      最近更新 更多