【问题标题】:Query runs fine in SQL Server but Errors in trying to read into a Pandas DF查询在 SQL Server 中运行良好,但尝试读入 Pandas DF 时出错
【发布时间】:2019-09-25 00:50:05
【问题描述】:

我有一个可以在 SQL Server 中正常运行的查询,但尝试使用 PYOBC 将其读入 DF 时出错。

我已将 SQL Server 中的确切查询复制并粘贴到我的 python 脚本中名为 query 的变量中(适用于所有其他查询)。

当我在 SQL Server 中运行查询时,这部分:

;WITH DeDupe AS (
    -- Trace 105704 was received, returned to vendor, and re-received under same PO. DeDupe handles this
    SELECT DISTINCT A.PurchaseOrderID, A.POLineNumber, D.TraceID
    FROM #UniquePOs A
    LEFT JOIN Trace.ReceivingReport B WITH (NOLOCK)
    ON A.PurchaseOrderID = B.PurchaseOrderID AND A.POLineNumber = B.POLineNumber
    LEFT JOIN Trace.EventInstance C WITH (NOLOCK)
    ON B.EventInstanceID = C.InstanceID AND C.EventID = 'RCVD' -- Keep only receive events, not project transfers to avoid double-counting
    LEFT JOIN Trace.Trace D
    ON C.TraceID = D.TraceID
)
SELECT * INTO #DeDupe FROM DeDupe

SELECT * FROM #DeDupe; <---I take this part out when I try to run the query to get the second table.

;WITH TraceQtys AS (
    -- Use this to solve Case 3 below
    SELECT A.PurchaseOrderID, A.POLineNumber, SUM(B.Quantity) AS 'SumOfTraceQty'
    FROM #DeDupe A
    LEFT JOIN Trace.Trace B
    ON A.TraceID = B.TraceID
    GROUP BY A.PurchaseOrderID, A.POLineNumber
)
SELECT * INTO #TraceQtys FROM TraceQtys

SELECT * FROM #TraceQtys;

将这些作为结果返回:

PurchaseOrderID                                    POLineNumber TraceID
-------------------------------------------------- ------------ -----------
007004                                             1            NULL
007004                                             1            41963

(2 rows affected)

Warning: Null value is eliminated by an aggregate or other SET operation.

(1 row affected)
PurchaseOrderID                                    POLineNumber SumOfTraceQty
-------------------------------------------------- ------------ ---------------------------------------
007004                                             1            8.00000

在我的 Python 脚本中运行:

query = 'SET NOCOUNT ON; ' + query
query = query.replace('GO', '')

conn = pyodbc.connect('Driver={ODBC Driver 17 for SQL Server};'
                      'Server=SL-SQL;'
                      'Database=TRACE DB;'
                      'Trusted_Connection=yes;')

df = pd.read_sql(query, conn)
df.head()

上面对第一个表返回相同的结果,但对第二个表返回错误:

TypeError: 'NoneType' 对象不可迭代

这个类似的查询在 Python 中有效:

query = '''
SET NOCOUNT ON;
WITH Temp as (
SELECT TraceID, ClassID, SUM(Quantity) as Q
FROM Trace.Trace
GROUP BY TraceID, ClassID
)
SELECT * INTO #Temp FROM Temp
SELECT * FROM #Temp'''

如果我在 Python 查询中去掉这部分,它也会运行:

SUM(B.Quantity) AS 'SumOfTraceQty'

我有一段类似的代码可以成功运行(进一步):

WITH POQtys AS (
    SELECT A.PurchaseOrderID, SUM(B.QtyVouched) AS POTotalQtyVouched
    FROM #orders A
    LEFT JOIN [MSS-ISD-DYN01].App.dbo.PurOrdDet B WITH (NOLOCK)
    ON A.PurchaseOrderID = B.PONbr AND B.InvtID IN ('DIR-MATERIALS', 'ASSET-INVENTORY')
    GROUP BY A.PurchaseOrderID
)
SELECT * INTO #POQtys FROM POQtys

【问题讨论】:

  • 尝试SUM(ISNULL(B.Quantity,0)) 在第二个CTE 解决您的警告。
  • @JIKEN,谢谢!这对我有用。我猜在 Python 中你不能对空值求和,而在 SQL Server 中你可以?
  • @JIKEN,发现 NULL 值之间的计算是我问题的根源:stackoverflow.com/questions/58107175/…
  • 所以,让我知道这个解决方案解决了您在进行任何聚合时是否解决了 NULL 值的根本问题。
  • @JIKEN,谢谢。您的解决方案在这里对我有帮助。更深层次的问题是 pd.read_sql 和 read_sql_query 在 NULL 中读取为 0。我环顾四周,似乎没有办法阻止这种情况。

标签: sql sql-server python-3.x pandas pyodbc


【解决方案1】:

对于 Python 游标调用,您通常一次只能提交一个 SQL 语句。因此,为什么其他人工作但不是你的组合,它维护多个 SQL 语句。但是,您可以在一个调用中使用多个甚至相互依赖的 CTE,并避免 SELECT...INTO 操作。

下面还使用更多信息表别名来消除A-B-C habitNo LOCK everywhere 的习惯。下面可以理解为 Pandas 的 read_sql 中的一个语句。

WITH DeDupe AS (
     SELECT DISTINCT u.PurchaseOrderID, u.POLineNumber, t.TraceID 
     FROM #UniquePOs u
     LEFT JOIN Trace.ReceivingReport r 
          ON u.PurchaseOrderID = r.PurchaseOrderID
          AND u.POLineNumber = r.POLineNumber 
     LEFT JOIN Trace.EventInstance e
          ON r.EventInstanceID = e.InstanceID 
          AND e.EventID = 'RCVD' 
     LEFT JOIN Trace.Trace t
          ON e.TraceID = t.TraceID 
), 
TraceQtys AS (
     SELECT d.PurchaseOrderID, d.POLineNumber, SUM(t.Quantity) AS 'SumOfTraceQty' 
     FROM DeDupe d
     LEFT JOIN Trace.Trace t
          ON d.TraceID = t.TraceID 
     GROUP BY d.PurchaseOrderID, t.POLineNumber
) 

SELECT * FROM TraceQtys

【讨论】:

  • 感谢您的意见。也许我应该更清楚。我根据是否要在 Python 脚本中显示 #DeDupe 表或 #TraceQtys 来切换代码中的 SELECT * FROM #DeDupe; 行。
  • 不确定您所说的 toggle 是什么意思,以及它如何适合 Pandas 数据框。也许为 DeDupeTraceQtys 数据帧运行 read_sql 两次?同样,您不能在游标调用中运行多个语句。
  • 是的,完全正确。我正在运行 read_sql 两次。每个 SELECT * FROM #____ 语句一次。我发现使用 NULL 值的计算是整个问题的根源。在这里创建了一个新问题:stackoverflow.com/questions/58107175/…
猜你喜欢
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-16
  • 2016-05-02
  • 1970-01-01
相关资源
最近更新 更多