Я играл с образцом базы данных электронной коммерции, который я перенес с сервера SQL на GraphDB. Я перевел SQL запросов на SPARQL, и у меня уже есть несколько из них. Однако мне трудно делать такие вещи, как вычисление промежуточных итогов, скользящих средних, номеров строк и ранжирования и т. Д. c. Прежде чем я объясню два нижеприведенных подзапроса, вот фрагмент модели:
product -> hasCategory -> category
order -> hasCustomer -> customer
Первый запрос работает нормально. Однако мне нужно найти альтернативу второму, где мне нужно вернуть два самых последних заказа для каждого клиента во внешнем запросе. В SQL одним из решений было бы использовать коррелированный запрос (передать идентификатор клиента внутреннему запросу для каждой записи внешнего запроса).
Я заметил несколько «проблем / предложений» для SPARQL , зарегистрировано ниже:
Я вижу, вы, ребята, принимали участие в некоторых из них.
# Query 1: Select all products that belong to the Seafood category
# WORKS FINE, as the inner query is completely independent of the outer one.
SELECT
?productName
?unitPrice
?unitsInStock
WHERE { # outer query
?product a :product ;
:productName ?productName ;
:unitPrice ?unitPrice ;
:unitsInStock ?unitsInStock ;
:hasCategory ?category .
{ # inner query
SELECT
?category
WHERE {
?category a :category ;
:categoryID ?categoryID ;
:name "Seafood" .
}
}
}
ORDER BY
?productName
# Query 2: Select the 3 most recent orders of each customer
# DOES NOT WORK!! It's a correlated query. SPARQL engine is not able to join the queries together.
SELECT DISTINCT
?customerID
?city
WHERE { # outer query
?customer a :customer ;
:customerID ?customerID ;
:city ?city ;
^:hasCustomer ?order .
{ # inner query
SELECT
?order
WHERE {
?order a :order ;
:orderID ?orderID ;
:orderDate ?orderDate ;
:hasCustomer ?customer .
}
ORDER BY
DESC(?orderDate)
LIMIT 3
}
}
ORDER BY
?customerID
?city
DESC(?orderDate)
Я мог бы использовать OVER PARTITION BY для замены подзапроса выше с тем же результатом в SQL. Собственно, в SQL есть много способов сделать это. Но в SPARQL я ничего не нашел. Вы, ребята, знаете способ обхода этой проблемы?
Большое спасибо,
Марсело.
PS: Я также оставляю SQL запросы здесь для справки (то же самое варианты использования решаются по-разному).
-- Query: Select all products that belong to the Seafood category
SELECT
prd.ProductName,
prd.UnitPrice,
prd.UnitsInStock
FROM
Product prd
WHERE
prd.CategoryID IN (
SELECT ctg.CategoryID FROM Category ctg WHERE ctg.CategoryName = 'Seafood')
ORDER BY
prd.ProductName
-- Query: Select all products that belong to the Seafood category
-- This query replaces the previous one by using the more efficient EXISTS
SELECT
prd.ProductName,
prd.UnitPrice,
prd.UnitsInStock
FROM
Product prd
WHERE
EXISTS (
SELECT 1 FROM Category ctg WHERE prd.CategoryID = ctg.CategoryID AND ctg.CategoryName = 'Seafood')
ORDER BY
prd.ProductName
-- Query: Select all products that belong to the Seafood category
-- Re-writting the previous query using JOIN
SELECT
prd.ProductName,
prd.UnitPrice,
prd.UnitsInStock
FROM
Product prd
INNER JOIN Category ctg
ON prd.CategoryID = ctg.CategoryID
WHERE ctg.CategoryName = 'Seafood'
ORDER BY
prd.ProductName
-- Query: Select the 3 most recent orders of each customer
SELECT
cst.CustomerID,
cst.City,
cpp.OrderID,
cpp.OrderDate
FROM
Customer AS cst
-- For each customer record, go and get the two most recent orders.
CROSS APPLY -- An INNER JOIN could've been used, however, CROSS APPLY is more efficient when combined with SELECT TOP.
(
SELECT TOP 3
ord.OrderID, ord.OrderDate, cst.CustomerID
FROM
[Order] AS ord
WHERE
ord.customerid = cst.customerid -- reference to the outer query (correlated subquery)
ORDER BY
ord.OrderDate DESC
) AS cpp
ORDER BY
cst.CustomerID,
cst.City,
cpp.OrderDate DESC
-- Windowed Functions
-- Calculating row numbering and ranking, quantiles, moving averages, and running totals.
-- Reference: https://docs.microsoft.com/en-us/sql/t-sql/queries/select-over-clause-transact-sql?view=sql-server-2017
-- Query: Select the 3 most recent orders of each customer
-- This query replaces the previous one by using the more efficient Windowed Function.
SELECT
ptt.*
FROM
(
SELECT
cst.CustomerID,
cst.City,
ord.OrderID,
ord.OrderDate,
ROW_NUMBER() OVER(PARTITION BY cst.CustomerID ORDER BY ord.OrderDate DESC) AS [RowNumber]
FROM Customer AS cst
INNER JOIN [Order] AS ord
ON cst.CustomerID = ord.CustomerID
) ptt
WHERE
ptt.[RowNumber] <= 3