php - 使用 ODBC 参数化案例语句
问题描述
我正在使用与此类似的查询从 MS SQL DB 中选择数据:
$result = odbc_prepare(
$connection,
"SELECT
t1.id, thumbnail, description, brand, vendor,
case
when ".implode(' AND ', $exactSearchTermDesc)." then 1
else 0
end as exactdescriptionmatch,
case
when ".implode(' AND ', $exactSearchTermMarkDesc)."". $exactThesaurusMarkDesc ."
then 1 else 0
end as exactcontentmatch,
case
when ".implode(' AND ', $searchTermDesc)."" . $thesaurusDesc ." then 1
else 0
end as descriptionmatch,
case
when ".implode(' AND ', $searchTermMarkDesc)."". $thesaurusMarkDesc ." then 1
else 0
end as contentmatch
FROM Martin.dbo.item_search"
);
odbc_execute($result);
如何参数化 case 语句中的变量?
例如,我尝试用这个参数化第一个变量无济于事......
$exactSearchTermDesc = implode(' AND ', $exactSearchTermDesc);
$result = odbc_prepare(
$connection,
"SELECT
t1.id, thumbnail, description, brand, vendor,
case when ? then 1 else 0 end as exactdescriptionmatch,
case when ".implode(' AND ', $exactSearchTermMarkDesc)."". $exactThesaurusMarkDesc ." then 1 else 0 end as exactcontentmatch,
case when ".implode(' AND ', $searchTermDesc)."" . $thesaurusDesc ." then 1 else 0 end as descriptionmatch,
case when ".implode(' AND ', $searchTermMarkDesc)."". $thesaurusMarkDesc ." then 1 else 0 end as contentmatch
FROM Martin.dbo.item_search"
);
odbc_execute($result array($exactSearchTermDesc));
变量如下。$terms 是用户输入。
$searchTerms = explode(' ', $terms);
$exactSearchTermDesc = array();
$exactSearchTermMarkDesc = array();
$searchTermDesc = array();
$searchTermMarkDesc = array();
foreach ($searchTerms as $term) {
$term = trim($term);
if (!empty($term)) {
$exactSearchTermDesc[] = "description LIKE '$term %'";
$exactSearchTermMarkDesc[] = "contains(marketingDescription, '$term')";
$searchTermDesc[] = "description LIKE '%$term%'";
$searchTermMarkDesc[] = "marketingDescription LIKE '%$term%'";
$searchTermVendor[] = "vendor LIKE '%$term%'";
}
}
$exactThesaurusDesc = " Or " . implode(' AND ', $exactThesaurusDesc);
$exactThesaurusMarkDesc = " Or " . implode(' AND ', $exactThesaurusMarkDesc);
$thesaurusDesc = " Or " . implode(' AND ', $thesaurusDesc);
$thesaurusMarkDesc = " Or " . implode(' AND ', $thesaurusMarkDesc);
$thesaurusVendor = " Or " . implode(' AND ', $thesaurusVendor);
解决方案
考虑重构您的 SQL 流程。与其在应用层(即 PHP)拼凑可能影响可读性和可维护性的动态 SQL 组件,不如考虑多个自连接到具有以下定义的临时术语表:
CREATE TABLE tmp_terms (
id IDENTITY(1,1) NOT NULL,
term VARCHAR(255),
thesauraus_indicator BIT
)
具体来说,跨MIN
返回 0 或 1 的连接匹配运行聚合查询。使用这种方法,可以维护相同的 SQL 查询,但 PHP 填充的基础术语将是动态组件。
CASE
下面运行之前逻辑的非词库部分。此外,由于CONTAINS
不能使用另一列而只能使用文字值,因此JOIN
表达式使用LIKE
前导通配符和尾随通配符。
SELECT
i.id, i.thumbnail, i.description, i.brand, i.vendor,
MIN(case
when exact_desc.term IS NOT NULL
then 1
else 0
end) AS exact_description_match,
MIN(case
when market_match.term IS NOT NULL
then 1
else 0
end) AS market_match,
MIN(case
when desc_match.term IS NOT NULL
then 1
else 0
end) AS desc_match,
MIN(case
when vendor_match.term IS NOT NULL
then 1
else 0
end) AS vendor_match
FROM Martin.dbo.item_search i
LEFT JOIN tmp_terms exact_desc
ON i.description LIKE CONCAT(exact_desc.term, ' %')
AND exact_desc.thesaurus_indicator = 0
LEFT JOIN tmp_terms market_match
ON i.marketingDescription LIKE CONCAT('%', market_match.term, '%')
AND market_match.thesaurus_indicator = 0
LEFT JOIN tmp_terms desc_match
ON i.description LIKE CONCAT('%', desc_match.term, '%')
AND desc_match.thesaurus_indicator = 0
LEFT JOIN tmp_terms vendor_match
ON i.vendor LIKE CONCAT('%', vendor_match.term, '%')
AND vendor_match.thesaurus_indicator = 0
GROUP BY i.id, i.thumbnail, i.description, i.brand, i.vendor
要集成词库匹配,请UNION
在外部查询聚合之前在 CTE 或子查询中使用。
WITH sub AS
(SELECT
i.id, i.thumbnail, i.description, i.brand, i.vendor,
exact_desc.term AS exact_desc_term, market_match.term AS market_match_term,
desc_match.term AS desc_match_term, vendor_match.term AS vendor_match_term
FROM Martin.dbo.item_search i
LEFT JOIN tmp_terms exact_desc
ON i.description LIKE CONCAT(exact_desc.term, ' %')
AND exact_desc.thesaurus_indicator = 0
LEFT JOIN tmp_terms market_match
ON i.marketingDescription LIKE CONCAT('%', market_match.term, '%')
AND market_match.thesaurus_indicator = 0
LEFT JOIN tmp_terms desc_match
ON i.description LIKE CONCAT('%', desc_match.term, '%')
AND desc_match.thesaurus_indicator = 0
LEFT JOIN tmp_terms vendor_match
ON i.vendor LIKE CONCAT('%', vendor_match.term, '%')
AND vendor_match.thesaurus_indicator = 0
UNION
SELECT
i.id, i.thumbnail, i.description, i.brand, i.vendor,
th_exact_desc.term, th_market_match.term,
th_desc_match.term, th_vendor_match.term
LEFT JOIN tmp_terms th_exact_desc
ON i.description LIKE CONCAT(th_exact_desc.term, ' %')
AND th_exact_match.thesaurus_indicator = 1
LEFT JOIN tmp_terms th_market_match
ON i.marketingDescription LIKE CONCAT('%', th_market_match.term, '%')
AND th_market_match.thesaurus_indicator = 1
LEFT JOIN tmp_terms th_desc_match
ON i.description LIKE CONCAT('%', th_desc_match.term, '%')
AND th_desc_match.thesaurus_indicator = 1
LEFT JOIN tmp_terms th_vendor_match
ON i.vendor LIKE CONCAT('%', th_vendor_match.term, '%')
AND th_vendor_match.thesaurus_indicator = 1
)
SELECT sub.id, sub.thumbnail, sub.description, sub.brand, sub.vendor,
MIN(case
when sub.exact_desc_term IS NOT NULL
then 1
else 0
end) AS exact_description_match,
MIN(case
when sub.market_match_term IS NOT NULL
then 1
else 0
end) AS market_match,
MIN(case
when sub.desc_match_term IS NOT NULL
then 1
else 0
end) AS desc_match,
MIN(case
when sub.vendor_match_term IS NOT NULL
then 1
else 0
end) AS vendor_match
FROM sub
GROUP BY sub.id, sub.thumbnail, sub.description, sub.brand, sub.vendor
注意:以上查询可能需要根据最终最终使用需求和测试进行调整。性能可能会因搜索词的数量而异。但最终,这个概念是与集合中的数据交互,而不是CASE WHEN...
与搜索词增长的长连接逻辑。
最后,在 PHP 中,只需使用参数化清理并使用新值填充临时表,然后运行上述任何最终查询:
odbc_exec($connection, "DELETE FROM tmp_terms");
$stmt = odbc_prepare($connection,
"INSERT INTO tmp_terms (term, thesaurus_indicator)
VALUES (?, ?)");
// NON-THESAURUS TERMS
foreach($search_terms as $t) {
odbc_execute($stmt, array($t, 0));
}
// THESAURUS TERMS
foreach($th_search_terms as $t) {
odbc_execute($stmt, array($t, 1));
}
// RUN FINAL SELECT QUERY
$result = odbc_exec($connection, "my_final_above_query");
while(odbc_fetch_row($result)){
for($i=1; $i<=odbc_num_fields($result); $i++){
// ... odbc_result($result,$i);
}
}
推荐阅读
- javascript - 如果文本超过,如何显示阅读更多和更少链接
- html - 垂直对齐文本和没有弹性框的框
- docker - 一个 docker 容器中的多个 Tors 服务
- javascript - 从字符串中删除 html 属性?
- tensorflow - sagemaker notebook 实例 Elastic Inference tensorflow 模型本地部署
- python - GTK3 GLArea 与 GLFW 的帧缓冲区问题(渲染到纹理):相同的 OpenGL 程序在 GLFW 中有效,但在 GTK3 的 GLArea 中无效
- python - 如何检查 python pandas 中的日期时间数据类型?
- javascript - 如何格式化 MM/YY 占位符作为用户类型?2M/YY -> 20/2Y -> 20/22
- vue.js - 为什么 Vue 有额外的
马上?它打破了 this.$root 完全 - angular - 从角度 8 更新后,列表单一选择在角度 9.1 中不起作用