我有一个搜索查询,包括一个表和两列。
Select *
from Gecoserv _a
where _a.typeOfEcosystem IN (:typeNameList)
AND _a.service IN (:serviceNameList)
它有效,但它没有给出我想要的结果
让我们说:
typeNameList = { Freshwater, Saltwater, Dunes }
serviceNameList = {Habitat, Food, Recreation }
我希望网格只显示单一组合(淡水 - 栖息地,咸水 - 食物和沙丘 - 休闲等),但它也显示其他组合(例如:淡水 - 娱乐)。
换句话说:查询结果显示
[0,0],[0,1],[0,2],
[1,0],[1,1],[1,2],
[2,0],[2,1],[2,2].
但我只想看到:[0,0],[1,1],[2,2]
。
我知道我必须在查询结束时添加一些内容。我尝试过很多东西,但无法找到完美的解决方案。
有没有人可以帮助我?
此致
Melih
答案 0 :(得分:0)
我认为这是你无法做到的唯一信息。参数值之间的关系是它们在列表中的位置。没有选项可以在SQL中关联和/或保留这些位置。
您对创建sql语句有什么影响?
如果你可以迭代代码中的列表并动态创建sql,你可以找到这样的解决方案:
SELECT * FROM Gecoserv
WHERE typeOfEcosystem = 'Freshwater' AND service = 'Habitat'
UNION
SELECT * FROM Gecoserv
WHERE typeOfEcosystem = 'Freshwater' AND service = 'Food'
UNION
...
有关如何参数化的示例,请查看this answer。
替代方法:拆分字符串
您的主要问题是保留其列表中参数的“等级”/“位置”。这可以通过用字符串替换列表并将其分解来完成。
我使用了example of a splitting a string in sql。
结果查询(使用this Fiddle制作)然后如下所示:
DECLARE
@ecoSystems varchar(100) = 'Freshwater,Saltwater,Dunes',
@services varchar(100) = 'Habitat,Food,Recreation',
@separator char(1) = ','
SELECT
[g].[id],
[g].[typeOfEcoSystem],
[g].[service]
FROM [dbo].[Split](@separator, @ecoSystems) [e]
INNER JOIN [dbo].[Split](@separator, @services) [s]
ON [e].[position] = [s].[position]
INNER JOIN [Gecoserv] [g]
ON [e].[part] = [g].[typeOfEcoSystem]
AND [s].[part] = [g].[service]
ORDER BY [id] ASC
这适合您的情况吗?(答案:是的,差不多......)
最后没有功能
DECLARE
@ecoSystems varchar(100) = 'Freshwater,Saltwater,Dunes',
@services varchar(100) = 'Habitat,Food,Recreation',
@separator char(1) = ',';
WITH [EcoSystemsAndServices]([posE], [startE], [endE], [posS], [startS], [endS])
AS
(
SELECT
1,
1,
CHARINDEX(@separator, @ecoSystems),
1,
1,
CHARINDEX(@separator, @services)
UNION ALL
SELECT
[posE] + 1,
[endE] + 1,
CHARINDEX(@separator, @ecoSystems, [endE] + 1),
[posS] + 1,
[endS] + 1,
CHARINDEX(@separator, @services, [endS] + 1)
FROM [EcoSystemsAndServices]
WHERE [endE] > 0
)
SELECT
[g].[id],
[g].[typeOfEcoSystem],
[g].[service]
FROM [Gecoserv] [g]
INNER JOIN [EcoSystemsAndServices] [ess]
ON [g].[typeOfEcoSystem] = SUBSTRING(@ecoSystems,
[startE],
CASE WHEN [endE] > 0 THEN [endE] - [startE] ELSE 100 END)
AND [g].[service] = SUBSTRING(@services,
[startS],
CASE WHEN [endS] > 0 THEN [endS] - [startS] ELSE 100 END)
ORDER BY [id] ASC
答案 1 :(得分:0)
如果没有任何支持架构甚至是数据库制造商,我的回复都必须对您的设置做出一些假设。
<强>理论
这听起来很像笛卡尔积。问题的关键在于你的IN条款是彼此独立的。因此,单个记录可以满足两个条件,但不是您希望在结果集中看到的。举个例子说我们有如下记录:
id name typeOfEcosystem service
-- ------------ --------------- ----------
1 myEcoService Freshwater Recreation
现在,您的查询将首先获取typeOfEcosystem(淡水)并检查它是否在您的列表中,它是什么。 结果:TRUE
然后,查询将获取服务(Recreation)并检查它是否在第二个列表中。再次,找到该值。 结果:TRUE
所有条件评估为true,因此该行包含在最终结果集中。
<强>解决方案
听起来我想要一个多列IN子句。请注意,这与您的尝试不同,因为最终解决方案应该只涉及单个IN关键字。现在,查询的确切形式将在很大程度上取决于您的数据库及其提供的内容。适用于任何符合SQL的数据库的解决方案是使用字符串操作。一个粗略的例子如下:
Select *
from Gecoserv _a
where _a.typeOfEcosystem || '-' || _a.service IN ('Freshwater-Habitat', 'Saltwater-Food', 'Dunes-Recreation')
在这个例子中,'||'假设是连接。这是非常便携的,但它很慢。问题可以更优雅地解决,但确切的解决方案将更多地取决于您的特定数据库和要求。例如,Oracle中的多列in子句可能很简单:
Select *
from Gecoserv _a
where (_a.typeOfEcosystem, _a.service) IN (('Freshwater', 'Habitat'), ('Saltwater', 'Food'), ('Dunes', 'Recreation'));
您可能必须按摩这些解决方案才能让它们与您的DBMS一起使用。更多技巧(以及普通的旧神阅读)可以在以下网址找到: