Возвращает только последний оператор из SQL-запроса Snowflake в R

#sql #r #odbc #snowflake-cloud-data-platform #snowflake-task

#sql #r #odbc #snowflake-cloud-data-platform #snowflake-задача

Вопрос:

У меня есть SQL-запрос Snowflake, который я пытаюсь выполнить в R через ODBC-соединение, который выглядит следующим образом

 SET quiet=TRUE;

USE SOMEDATABASE.SOMESCHEMA;

--Select timestamp of last sale per customer
DROP TABLE IF EXISTS sales;
CREATE TEMPORARY TABLE sales(CustomerId VARCHAR(16777216), SaleTS TIMESTAMP_NTZ(9));

INSERT INTO sales
SELECT CustomerId, 
       SaleTS
FROM SALES
WHERE SaleTS>= '2020-11-19 00:00:00'
AND SaleTS <= '2020-11-19 23:59:59.999'
GROUP BY CustomerId;

--Use temp table to get correct row from sales table
SELECT  SUM(SalesDetail.price) as SumPrice
        COUNT(*) as SoldVolume
FROM sales
LEFT JOIN SALES as SalesDetail
    ON Sales.CustomerId = SalesDetail.CustomerId 
    AND sales.SaleTS = SalesDetail.SaleTS 
 

Запрос Microsoft SQL Server из R, который я обычно включаю set nocount no; в начало запроса, чтобы гарантировать, что в R возвращается только последний шаг, чтобы избежать ошибки Actual statement count 6 did not match the desired statement count 1. Ошибка имеет смысл, SQL возвращает 6 компонентов, когда R ожидает 1 (6 по одному для каждого шага в моем SQL-запросе). В Snowflake, похоже, нет возможности установить nocount таким же образом. Мой вопрос заключается в том, как мне избежать вышеуказанной ошибки. Есть ли у кого-нибудь опыт выполнения многоступенчатого SQL-запроса Snowflake через R? Как я могу заставить R получать только последнее утверждение от соединения ODBC. До сих пор я пробовал set nocount=TRUE; , set echo=FALSE; , set message=FALSE; , SET quiet=TRUE и т. Д

Комментарии:

1. вы вставляете из той же таблицы во временную таблицу и присоединяетесь обратно к той же таблице? почему бы просто не получить сумму и не посчитать напрямую?

2. а также SET NOCOUNT ON возможность просто получать сообщения о количестве сообщений, возвращаемых sql, а не результат, если у вас есть несколько заданных результатов (несколько выборок), возвращающихся обратно из sql, вы все равно получите нулевой набор результатов в вашем выводе

3. Это всего лишь пример, мой фактический сценарий длиннее и включает в себя более 1 таблицы. Действительно хотелось бы решить проблему с несколькими шагами. Существует множество веских причин структурировать SQL-запрос таким образом, а не использовать сильно вложенный подход с одним запросом.

4. R видит сообщения как выходные данные, и это тот момент, когда мне нужно остановить сообщения.

Ответ №1:

Snowflake SQL достаточно выразителен, и предлагаемый код может быть структурирован как один запрос:

 WITH cte AS (
    SELECT CustomerId, MAX(SaleTS) AS SaleTS  -- here agg function is required
    FROM SALES
    WHERE SaleTS>= '2020-11-19 00:00:00'
    AND SaleTS <= '2020-11-19 23:59:59.999'
    GROUP BY CustomerId
)
SELECT  SUM(SalesDetail.price) as SumPrice
        COUNT(*) as SoldVolume
FROM cte
LEFT JOIN SALES as SalesDetail
    ON Sales.CustomerId = SalesDetail.CustomerId 
    AND sales.SaleTS = SalesDetail.SaleTS;
 

Исходный запрос использует одно и то же имя как для таблицы, так и для временной таблицы, отличаясь только регистром sales vs SALES , что может привести к ошибкам.

Во-вторых: база данных и схема могут быть настроены во время установления соединения, поэтому нет необходимости во USE внутреннем скрипте. В качестве альтернативы в скрипте может использоваться полное имя.


Я предполагаю, что цель запроса заключается в следующем:

 WITH cte AS (
  SELECT *
  FROM SOMEDATABASE.SOMESCHEMA.SALES
  WHERE SaleTS BETWEEN '2020-11-19 00:00:00' AND '2020-11-19 23:59:59.999'
  QUALIFY ROW_NUMBER() OVER(PARTITION BY CustomerId ORDER BY SaleTS DESC) = 1
)
SELECT COUNT(*) AS SoldVolume, SUM(price) as SumPrice
FROM cte;
 

Если возможно, что у одного человека есть две записи для одних и тех же продаж, тогда RANK() OVER(...) их следует использовать вместо этого.

Комментарии:

1. Хорошее использование with , я понимаю вашу точку зрения, что таким образом вы можете устранить необходимость во временных таблицах.

2. Обратите внимание, что с Oracle мне часто приходится делать SELECT * FROM (WITH cte as (...)) то, что, по-видимому, ожидают драйверы SELECT при вызове из R (или VBA). К вашему сведению, на случай, если OP столкнется с этим в R. 1, поскольку SQL более выразителен, чем люди обычно считают.