【问题标题】:SQL VBA Query Will Only Return Results on Small DatasetSQL VBA 查询将只返回小数据集的结果
【发布时间】:2018-07-09 19:10:14
【问题描述】:

我正在构建一个可以为我的团队自动生成报告的宏。第一部分设置为根据在对话框中选择的唯一标识符查询 SQL(使用 MS SQL Server Management Studio),然后将这些结果提供给步骤 2。

在构建宏时,我注意到当唯一标识符列表低于 9,000 时,查询会按预期返回结果。但是,如果我尝试查询超过 9000 行的任何内容,宏将运行而不会出现错误,但它不会返回结果,而是只显示最后一个活动窗口。基本上看起来宏什么也没做。

由于宏在小型数据集上完美运行并且没有错误,我对如何使其在大型数据集上运行感到有些困惑。我们的报告通常超过 10,000 行。会不会是我的参考?任何见解将不胜感激。如果需要额外的见解,请告诉我。

编辑:

当前代码如下

Sub FilterLov1()
    Dim rng As Range
    Dim workrng As Range
    Dim workrng1 As String
    Dim today As String
    Dim lastRow As Long
    Dim dept As String
    Dim class As String
    Dim subclass As String
    Dim sSQL As String
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim wsname As String

    wsname = ActiveSheet.Name

    'Set omsid list for SQL query
    On Error GoTo Handler
    Set workrng = Application.InputBox("Range:", Type:=8)
    Application.ScreenUpdating = False

    'Set rng = ActiveSheet.Range(workrng)

    Dim mystring As String
    mystring = RangeToString(workrng)

    'Declare the SQL code here

    Set cn = New ADODB.Connection
    cn.Open "Provider=SQLOLEDB;Data Source=WAPRCN026A;Initial Catalog= STEP_MVIEWS;Integrated Security=SSPI"

    sSQL = "select NAME, GuidID, DATASTANDARDS_PATH, PRODUCT_NAME_120, MARKETING_COPY, BULLET01, BULLET02, BULLET03, BULLET04, BULLET05, BULLET06, WORKFLOWSTATE, CHANNELSTATUS, THDONLINESTATUS from STEP_MVIEWS.dbo.[OMSID TO DATASTANDARDS] inner join STEP_MVIEWS.dbo.SCORECARD10_APPROVED on name = OMSID where [omsid] in (" & mystring & ")"

    Set rs = New ADODB.Recordset
    rs.Open sSQL, cn

        'Sheets.Add After:=ActiveSheet

    Worksheets.Add.Name = "FiltersLOVRaw"
    Worksheets("FiltersLOVRaw").Cells(1, 1).CopyFromRecordset rs

    rs.Close
    Set rs = Nothing
    cn.Close
    Set cn = Nothing

    Cells.Select


    'Add Column Headers here for export file
    Sheets("FiltersLOVRaw").Select
    Rows("1:1").Select
    Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
    Cells(1, 1).value = "OMSID"
    Cells(1, 2).value = "PARENT LEAF GUID"
    Cells(1, 3).value = "FILE PATH"
    Cells(1, 4).value = "PRODUCT NAME (120)"
    Cells(1, 5).value = "MARKETING COPY (1500)"
    Cells(1, 6).value = "BULLET 01"
    Cells(1, 7).value = "BULLET 02"
    Cells(1, 8).value = "BULLET 03"
    Cells(1, 9).value = "BULLET 04"
    Cells(1, 10).value = "BULLET 05"
    Cells(1, 11).value = "BULLET 06"
    Cells(1, 12).value = "WORKFLOW STATUS"
    Cells(1, 13).value = "CHANNEL STATUS"
    Cells(1, 14).value = "THD ONLINE STATUS"

    Cells.Select


    With ActiveSheet
        lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
    End With

    'Sheets.Add
    'ActiveSheet.Name = "Export"

    'Rows(x - 1).EntireRow.Delete
    'Cells.Select
        Range("A1").Select

Handler:
    Exit Sub
End Sub
Function RangeToString(ByVal MyRange As Range) As String
    RangeToString = ""
    If Not MyRange Is Nothing Then
        Dim myCell As Range
        For Each myCell In MyRange
            RangeToString = RangeToString & ",'" & myCell.value & "'"
        Next myCell
        'Remove extra comma
        RangeToString = Right(RangeToString, Len(RangeToString) - 1)
        'RangeToString = Left(RangeToString, Len(RangeToString) - 1)
    End If
End Function

【问题讨论】:

  • 有任何代码 sn-ps 来调查吗?你的意思是一个返回 9000 行的查询,还是你的意思是查询 9000 行,因为 ID 是他们的唯一 ID? (我想你的意思是后者,只是想澄清一下)
  • 这肯定就像内存缓冲区溢出一样。失败时的实际查询字符串有多大 - 我目前正在下注大约 65,535 字节长。
  • 查询是一个简单的选择语句,用于检索数量不同的产品 ID 列表的数据,但该列表始终包含超过 10,000 个产品 ID。到目前为止,当我查询超过 9,000 行的任何内容时,宏都会失败而没有任何错误消息。但是,当我直接在 SQL 中查询时,我会在不到 2 分钟的时间内获得完整测试数据集(12,048 行)的结果。我希望将查询内置到报告中以尽可能地自动化它。我现在要添加代码了。

标签: sql sql-server vba excel


【解决方案1】:

我知道在 Oracle 中使用 SELECT IN 子句时有 1,000 个值的限制。

根据this post 有一个限制(在 SQL Server 中),数以千计。它建议将 ID 列表加载到表中,然后对该表进行查询。

【讨论】:

    【解决方案2】:

    在括号中显式包含大量值(以逗号分隔的数千个值),在 IN 子句中会消耗资源并返回错误 8623 或 8632。

    错误 8623:

    The query processor ran out of internal resources and could not produce a query plan. This is a rare event and only expected for extremely complex queries or queries that reference a very large number of tables or partitions. Please simplify the query. If you believe you have received this message in error, contact Customer Support Services for more information.
    

    错误 8632:

    Internal error: An expression services limit has been reached. Please look for potentially complex expressions in your query, and try to simplify them.
    

    要解决此问题,请将 IN 列表中的项目存储在表中,并在 IN 子句中使用 SELECT 子查询。

    参考Microsoft docs


    可以在 SQL Server Management Studio 中运行的示例
    (或者如果您没有(它们是免费的)SSMS 版本,则直接从 Excel 中针对数据库)。
    如果您想保留这些表,请注释掉 DROP 语句。

    --Sample SQL https://stackoverflow.com/questions/51252536/sql-vba-query-will-only-return-results-on-small-dataset/
    IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = N'CC') 
    BEGIN
    -- Create a new schema name so it does not interfere with existing tables
    EXEC sys.sp_executesql N'CREATE SCHEMA [CC] AUTHORIZATION [dbo]'
    
    -- Create the table that holds the values which your user chooses
    CREATE TABLE [CC].[KeyList]([RowKeysYouWant] [int] NOT NULL) ON [PRIMARY]
    ALTER AUTHORIZATION ON [CC].[KeyList] TO  SCHEMA OWNER
    
    -- This is the existing table which has your data in it
    CREATE TABLE [CC].[TableWithData]([pk] [int] NOT NULL,
        [data1] [char](2) NULL,[data2] [char](2) NULL) ON [PRIMARY]
    ALTER AUTHORIZATION ON [CC].[TableWithData] TO  SCHEMA OWNER 
    
    -- here are the rows that you want (put list of chosen items in here)
    INSERT [CC].[KeyList] ([RowKeysYouWant]) VALUES (1),(2),(3),(5),(7)
    -- this is your data table (fields data1 and data2 become null by default)
    INSERT [CC].[TableWithData] ([pk]) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9)
    
    -- This is the select you use to grab all the records in table KeyList
    SELECT * FROM CC.TableWithData WHERE pk IN (SELECT RowKeysYouWant FROM CC.KeyList)
    
    DROP TABLE [CC].[TableWithData]; DROP TABLE [CC].[KeyList]; DROP SCHEMA [CC]
    END
    GO
    

    您需要权限才能创建架构并创建表来运行它。
    如果您在工作中没有这些权限,只需在您的家用 PC 上安装 SQL Server Express 版本的副本并在那里运行脚本。
    先让你的 SQL 工作,然后再考虑如何让它在 VBA 中工作。 :-)

    【讨论】:

    • 感谢您的反馈。我不熟悉此所需的语法。您介意发布示例查询吗?我一直在尝试以下查询的变体,但没有运气。我不断收到错误消息 2,“'0' 附近的语法不正确。查询:从 (Select NAME, GuidID, DATASTANDARDS_PATH, PRODUCT_NAME_120, MARKETING_COPY, BULLET01, BULLET02, BULLET03, BULLET04, BULLET05, BULLET06, WORKFLOWSTATE, CHANNELSTATUS,来自 aaa.dbo.[ABCDEFG] 的 THDONLINESTATUS 内部连接 ​​bbb.dbo.[HIJKLMNOP] on name = OMSID where omsid in ('123456789'))
    • 我将在答案中添加一个示例。简而言之:您会将所需的键插入表(标准或临时表;我的示例是标准的)。您所存储的只是密钥列表(如果您有复合密钥,则需要多个字段)。然后,您将使用该键列表来获取您的实际数据行。
    猜你喜欢
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多