三條 SQL 降級查詢:
1. 查詢 Bgoods 表 (本地商品),有數據返回前 20 條 + 總數。
2. 無數據則查 prodh.dbo.G1982 (異庫商品),返回前 20 條 + 總數。
3. 仍無數據則查 Bgoods 不限距離/分類,返回前 20 條。
CREATE PROCEDURE dbo.usp_GetGoods_Fallback
@Lng DECIMAL(18,14),
@Lat DECIMAL(18,14),
@Keyword NVARCHAR(50),
@PageSize INT = 20
AS
BEGIN
SET NOCOUNT ON;
-- 臨時表存儲最終結果
CREATE TABLE #Result (
company NVARCHAR(50), code NVARCHAR(50), name NVARCHAR(100),
hyprice DECIMAL(18,2), comeFrom NVARCHAR(50), finish NVARCHAR(50),
smallfanwei NVARCHAR(50), distance DECIMAL(18,6),
rn INT IDENTITY(1,1) -- 行號用於分頁
);
-- 1. 第一優先級查詢
INSERT INTO #Result (company, code, name, hyprice, comeFrom, finish, smallfanwei, distance)
SELECT TOP (@PageSize)
a.company, a.code, a.name, b.hyprice, a.comeFrom,
ISNULL(a.finish,''), c.smallfanwei,
dbo.GetDistancefromLnglat(@Lng, @Lat, c.lng, c.lat)/1000.0
FROM Bgoods a
JOIN Bgoodsdtl b ON a.code=b.code AND a.company=b.company
JOIN shopperA c ON a.company=c.SEQ
WHERE (c.lng BETWEEN @Lng-0.0488 AND @Lng+0.0488) -- 經度範圍約 5km
AND (c.lat BETWEEN @Lat-0.0449 AND @Lat+0.0449) -- 緯度範圍約 5km
AND a.KgCN = @Keyword
AND b.display IN ('1','2','3')
AND dbo.GetDistancefromLnglat(@Lng, @Lat, c.lng, c.lat)/1000.0 <= 5
ORDER BY distance;
IF EXISTS (SELECT 1 FROM #Result)
BEGIN
SELECT * FROM #Result WHERE rn BETWEEN 1 AND @PageSize;
SELECT COUNT(*) AS TotalCount FROM #Result;
DROP TABLE #Result;
RETURN;
END
-- 2. 第二優先級查詢 (清空臨時表重用)
TRUNCATE TABLE #Result;
INSERT INTO #Result (company, code, name, hyprice, comeFrom, finish, smallfanwei, distance)
SELECT TOP (@PageSize)
a.company, a.code, a.oldcode, a.name, b.hyprice, a.comeFrom,
ISNULL(a.finish,''), NULL, -- 此表無 smallfanwei
dbo.GetDistancefromLnglat(@Lng, @Lat, c.lng, c.lat)/1000.0
FROM prodh.dbo.G1982 a
JOIN prodh.dbo.G1982dtl b ON a.code=b.code
JOIN shq520.dbo.ghuser c ON a.company=c.SEQ
WHERE (c.lng BETWEEN @Lng-0.0488 AND @Lng+0.0488)
AND (c.lat BETWEEN @Lat-0.0449 AND @Lat+0.0449)
AND a.name LIKE '%' + @Keyword + '%'
AND b.dhdisplay = '1'
AND dbo.GetDistancefromLnglat(@Lng, @Lat, c.lng, c.lat)/1000.0 <= 5
ORDER BY distance;
IF EXISTS (SELECT 1 FROM #Result)
BEGIN
SELECT * FROM #Result WHERE rn BETWEEN 1 AND @PageSize;
SELECT COUNT(*) AS TotalCount FROM #Result;
DROP TABLE #Result;
RETURN;
END
-- 3. 第三優先級查詢 (兜底)
TRUNCATE TABLE #Result;
INSERT INTO #Result (company, code, name, hyprice, comeFrom, finish, smallfanwei, distance)
SELECT TOP (@PageSize)
a.company, a.code, a.name, b.hyprice, a.comeFrom,
ISNULL(a.finish,''), c.smallfanwei,
dbo.GetDistancefromLnglat(@Lng, @Lat, c.lng, c.lat)/1000.0
FROM Bgoods a
JOIN Bgoodsdtl b ON a.code=b.code AND a.company=b.company
JOIN shopperA c ON a.company=c.SEQ
WHERE b.display IN ('1','2','3')
AND (c.lng BETWEEN @Lng-0.0488 AND @Lng+0.0488)
AND (c.lat BETWEEN @Lat-0.0449 AND @Lat+0.0449)
ORDER BY distance;
SELECT * FROM #Result WHERE rn BETWEEN 1 AND @PageSize;
SELECT COUNT(*) AS TotalCount FROM #Result;
DROP TABLE #Result;
END
SQL Server 無「無數據異常」,SELECT 返回空結果集**不拋異常**。強行用 RAISERROR 模擬異常流程屬於濫用異常控制流,**極不推薦**。
distance 列過濾/排序,避免 ORDER BY dbo.GetDistance... 導致全表掃描無法用索引。shopperA(lng, lat)、ghuser(lng, lat) 建立空間索引或復合索引,配合經緯度範圍過濾 (BETWEEN) 命中索引求交集。TRUNCATE TABLE #Result 比 DROP/CREATE 快,保留統計信息。SQL Server 存儲過程多條件降級查詢,核心模式: 臨時表存結果 → INSERT TOP(N) 第一優先級 → IF EXISTS 判斷有無數據 → 有則返回退出 → 無則 TRUNCATE 臨時表 → 繼續下一優先級。
**拒絕用 TRY-CATCH 模擬業務流程**,IF EXISTS 語義清晰、性能最優、易維護。