动态数据透视表 - 仅在需要时显示字段

时间:2017-11-21 16:52:22

标签: sql sql-server vb.net

我在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 and Between,但我不能让它正常工作。

结果显示在Excel中。 DatePicker工作得很好,SQL确实按照我的要求做了,但它显示了一年中的所有月份,即使我选择了,让我们说9/1/17到11/20/17。有没有办法让枢轴场动态,以及动态日期。或者我是否必须按原样运行它,并删除Excel中第2行为空的任何列,或者某些类似的东西?我想只显示startDate和endDate之间的数据。感谢。

2 个答案:

答案 0 :(得分:1)

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

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

<强>解释

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

    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
    

    希望这会对你有所帮助

答案 1 :(得分:0)

包含带有select:

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

......不行吗?