我是关于stackexchange的第一个问题,因为我在这件事上挣扎了几天:
我想在具有 col1,col2,col3,col4,col5 的表上进行复杂查询(PLSQL),其值为(名称:每列拆分一个部分)< / p>
+------+--------+--------+--------+------+
| ID | Col1 | Col2 | Col3 | Col4 |
+------+--------+--------+--------+------+
| (#1) | Andrew | Joan | Bach | Mike |
| (#2) | Mark | Andrew | Livy | |
| (#3) | Joan | Arch | Donnie | |
| (#4) | Joan | Andrew | Lyx | |
+------+--------+--------+--------+------+
名称部分的数量从1到5不等。
我想搜索不同的组合:
我不喜欢使用looooong查询的想法,我将编写所有可能的排列以便为搜索字符串的每个部分加工
我想要实现的目标是:
我使用ORACLE数据库,我正在考虑在存储过程中创建它:match_my_set(query_str,col1,col2,col3,col4,col5)。我会写至少5个循环(循环到循环)以实现这一点,但我怀疑这是一个专业的想法。
感谢任何帮助。谢谢
答案 0 :(得分:5)
如果您使用11g或更高版本,则可以将列拆分为行;这是使用CTE提供您的样本数据:
with t (id, col1, col2, col3, col4, col5) as (
select 1, 'Andrew', 'Joan', 'Bach', 'Mike', null from dual
union all select 2, 'Mark', 'Andrew', 'Livy', null, null from dual
union all select 3, 'Joan', 'Arch', 'Donnie', null, null from dual
union all select 4, 'Joan', 'Andrew', 'Lyx' , null, null from dual
)
select * from t
unpivot (name for col_no in (col1 as 1, col2 as 2, col3 as 3, col4 as 4, col5 as 5));
ID COL_NO NAME
---------- ---------- ------
1 1 Andrew
1 2 Joan
1 3 Bach
1 4 Mike
2 1 Mark
2 2 Andrew
2 3 Livy
...
然后,您可以查找单个名称列的匹配项:
select distinct id
from (
select * from t
unpivot (name for col_no in (col1 as 1, col2 as 2, col3 as 3, col4 as 4, col5 as 5))
)
where name in ('Bach', 'Joan', 'Mike')
order by id;
ID
----------
1
3
4
我想你希望通过计算每行中匹配的术语数量来使排序更复杂。如果是这样,你可以这样做:
select id, count(*) as cnt
from (
select * from t
unpivot (name for col_no in (col1 as 1, col2 as 2, col3 as 3, col4 as 4, col5 as 5))
)
where name in ('Bach', 'Joan', 'Mike')
group by id;
ID CNT
---------- ----------
1 3
4 1
3 1
然后有另一个级别的内联视图按顺序排序,以某种方式打破关系:
select id
from (
select id, count(*) as cnt
from (
select * from t
unpivot (name for col_no in (col1 as 1, col2 as 2, col3 as 3, col4 as 4, col5 as 5))
)
where name in ('Bach', 'Joan', 'Mike')
group by id
)
order by cnt desc, id;
与样本数据的结果相同。将IN
条件更改为用户('Andrew', 'Bach')
也会在两个版本中获得1,2,4。
根据您获取所搜索的值的方式,您可能希望使用数组(通过表集合表达式和连接),或者标记包含所有搜索词的字符串,或其他一些变化
答案 1 :(得分:3)
您可以使用Oracle的集合(应该在10g或更高版本中运行)
Oracle安装程序:
CREATE TABLE TABLE_NAME( ID, Col1, Col2, Col3, Col4 ) AS
SELECT 1, 'Andrew', 'Joan', 'Bach', 'Mike' FROM DUAL UNION ALL
SELECT 2, 'Mark', 'Andrew', 'Livy', NULL FROM DUAL UNION ALL
SELECT 3, 'Joan', 'Arch', 'Donnie', NULL FROM DUAL UNION ALL
SELECT 4, 'Joan', 'Andrew', 'Lyx', NULL FROM DUAL;
CREATE TYPE stringlist AS TABLE OF VARCHAR2(100);
/
<强>查询强>:
SELECT id,
col1,
col2,
col3,
col4
FROM (
SELECT t.*,
stringlist( col1, col2, col3, col4 )
MULTISET INTERSECT
stringlist( 'Bach', 'Joan', 'Mike' ) -- Search terms
AS names
FROM TABLE_NAME t
)
WHERE names IS NOT EMPTY
ORDER BY CARDINALITY( names ) DESC, ID;
<强>输出强>:
ID COL1 COL2 COL3 COL4
---------- ------ ------ ------ ----
1 Andrew Joan Bach Mike
3 Joan Arch Donnie
4 Joan Andrew Lyx
答案 2 :(得分:-1)
这是未经测试的,但我认为它会起作用。首先,您需要一个将空格中的搜索字符串拆分为表格的函数:
CREATE function [dbo].[SplitSpace] (@StringList varchar(4000))
RETURNS @Result Table(Value varchar(50))
AS
BEGIN
DECLARE @x XML
SELECT @X = CAST('<A>' + REPLACE(@StringList, ' ', '</A><A>') + '</A>' AS XML)
INSERT INTO @Result
SELECT t.value('.', 'varchar(50)') as inVal
FROM @X.nodes('/A') AS x(t)
RETURN
END
此功能在其他地方也会派上用场,如果需要,您可以轻松地将其修改为逗号或任何其他值。
接下来,您需要创建一个返回所需结果的查询(当您完成测试时,您可以将其转换为存储过程并接受搜索字符串作为参数):
DECLARE @SearchString varchar(255) = 'Bach Joan Mike'
DECLARE @SearchTable TABLE(Value varchar(50))
INSERT INTO @SearchTable
SELECT DISTINCT Value
FROM SplitSpace(@SearchString)
SELECT DISTINCT Col1, Col2, Col3, Col4
FROM MyTable M
JOIN @SearchTable S
ON S.Value = Col1
OR S.Value = Col2
OR S.Value = Col3
OR S.Value = Col4
CROSS APPLY
(
SELECT COUNT(*) AS [Number of Hits]
FROM @SearchTable
WHERE Value = M.Col1
OR Value = M.Col2
OR Value = M.Col3
OR Value = M.Col4
) t
ORDER BY t.[Number of Hits] DESC
基本上,你说“给我所有记录,其中一个或多个”名称“列存在于搜索字符串中。
然后,你说,通过Cross Apply,“对于每一行,告诉我我有多少次点击”。然后,您所要做的就是按命中次数排序,然后您就完成了设置。
注意:有人可能会输入“Andrew Andrew Bach”作为搜索字符串。如果他们这样做了,那么每个列中都会有2次点击,其中包含安德鲁,每个列只有一个符合巴赫。这就是你从函数返回表中选择不同值的原因;它消除了那些重复。此外,如果你有多个匹配,你会得到两次返回的记录,因为它是一个内连接,所以你从这些结果中选择不同的col1,col2,col3,col4,以消除那些重复。
如果您有任何疑问,请与我们联系。