Closed. This question is not reproducible or was caused by typos . It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed yesterday.
This post was edited and submitted for review yesterday.
Improve this question
I am building a dynamic product search query using c# and dapper. I am trying to use a Common Table Expression to filter the product results, and then to order the filtered results, and implement pagination on them.
I keep getting the error:
SqlException: The column 'ProductId' was specified multiple times for 'FilteredResults'.
Here is my query:
DECLARE @queryRows AS INT = 5;
DECLARE @queryOffset AS INT = 0;
WITH FilteredResults AS
(
SELECT p.*, pv.*
FROM Products p
LEFT JOIN ProductVariants pv ON p.ProductId = pv.ProductId
LEFT JOIN ProductCategories pc ON p.ProductId = pc.ProductId
LEFT JOIN ProductDescriptions pd ON p.ProductId = pd.ProductId
WHERE 1 = 1
AND pc.CategoryId = @categoryId
AND (p.ProductName LIKE @searchText OR pd.Description LIKE @searchText)
)
SELECT
*, p.ProductId AS ProductIdAlias
FROM
FilteredResults
ORDER BY
p.ProductIdAlias
OFFSET @queryOffset ROWS
FETCH NEXT @queryRows ROWS ONLY;
I am trying to use an alias, but it is not working. If I remove the ORDER BY p.ProductId
clause in the pagination query, I then get this error:
SqlException: Incorrect syntax near '@queryOffset'.
Invalid usage of the option NEXT in the FETCH statement.
Here is the working query:
WITH FilteredProducts AS (
SELECT
p.ProductId,
p.ProductName
FROM Products p
LEFT JOIN ProductCategories pc ON p.ProductId = pc.ProductId
LEFT JOIN ProductDescriptions pd ON p.ProductId = pd.ProductId
WHERE 1 = 1
AND pc.CategoryId = @categoryId
AND (p.ProductName LIKE @searchText OR pd.DescriptionBody LIKE @searchText)
)
SELECT
p.ProductId,
p.ProductName,
(
SELECT
pv.VariantId,
pv.VariantName,
pv.VariantPriceMain
FROM ProductVariants pv
WHERE p.ProductId = pv.ProductId
FOR XML PATH('Variant'), ROOT('Variants'), TYPE
) AS Variant
FROM FilteredProducts p
WHERE EXISTS (
SELECT 1
FROM ProductVariants pv
WHERE p.ProductId = pv.ProductId
AND pv.VariantPriceMain >= @minPrice
);
1条答案
按热度按时间ecfdbz9o1#
When you have a CTE like this
The table alias
p
within the CTE is no longer valid outside the CTE. That is, you cannot do this:All you can do is this:
or this:
This is because
p
no longer exists for the outer level. This is true even if there were multiple tables used in the CTE. The original table names used inside the CTE are no longer relevantoutside the CTE.Additionally, column names returned from the CTE must be unique. If you have two tables in the CTE that both have columns with the same name, it is not enough to reference them separately by their table in the CTE's
SELECT
clause.That is, you cannot do this:
And you cannot do this (if there are shared column names):
Which means you definitely cannot do this:
Because all three snippets cause you to have two columns with the same
ProductID
name.This should be obvious once we understand the first section about table names and aliases. If neither
t1
nort2
exist outside the CTE as usable identifiers, then neither dot1.ProductID
ort2.ProductID
. All you have iscte.ProductID
, and this is ambiguous; it could reference the column from either table, and that's not legal.Instead, you need to manually list out all the columns you need from both source tables, so no names are duplicated. This has always been the better option , even when no CTEs or duplicate column names are involved. Additionally, make sure to only reference the CTE itself outside of the CTE, rather than the source tables.
So it would look like this:
For your query, it will looks like this (with the exception that you will want to add back more of the columns):