#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 более выразителен, чем люди обычно считают.