سؤال تحليلي أوراكل
-
06-07-2019 - |
سؤال
بالنظر إلى وظيفة zipdistance(zipfrom,zipto) التي تحسب المسافة (بالأميال) بين رمزين بريديين والجداول التالية:
create table zips_required(
zip varchar2(5)
);
create table zips_available(
zip varchar2(5),
locations number(100)
);
كيف يمكنني إنشاء استعلام يعيد لي كل رمز بريدي من الجدول zips_required والحد الأدنى للمسافة التي قد تنتج مجموعًا (مواقع) >= n.
حتى الآن قمنا بتشغيل استعلام حلقة شاملة لكل نصف قطر حتى نحقق المعايير.
--Do this over and over incrementing the radius until the minimum requirement is met
select count(locations)
from zips_required zr
left join zips_available za on (zipdistance(zr.zip,za.zip)< 2) -- Where 2 is the radius
قد يستغرق هذا بعض الوقت على قائمة كبيرة.يبدو أنه يمكن القيام بذلك باستخدام استعلام تحليلي أوراكل على غرار:
min() over (
partition by zips_required.zip
order by zipdistance( zips_required.zip, zips_available.zip)
--range stuff here?
)
الاستعلامات التحليلية الوحيدة التي قمت بها كانت تعتمد على "رقم الصف (التقسيم حسب الترتيب)"، وأنا أسير في مناطق غير معروفة بهذا.أي توجيه في هذا الشأن هو موضع تقدير كبير.
المحلول
هذا هو ما خطرت لي :
SELECT zr, min_distance
FROM (SELECT zr, min_distance, cnt,
row_number() over(PARTITION BY zr ORDER BY min_distance) rnk
FROM (SELECT zr.zip zr, zipdistance(zr.zip, za.zip) min_distance,
COUNT(za.locations) over(
PARTITION BY zr.zip
ORDER BY zipdistance(zr.zip, za.zip)
) cnt
FROM zips_required zr
CROSS JOIN zips_available za)
WHERE cnt >= :N)
WHERE rnk = 1
- لكل
zip_required
حساب المسافة إلىzip_available
وفرزها حسب المسافة - لكل
zip_required
الcount
معrange
يسمح لك بمعرفة كمzip_availables
تقع في دائرة نصف قطرها تلك المسافة. - عامل التصفية (أولاً حيث COUNT(locations) > N)
اعتدت على إنشاء بيانات العينة:
INSERT INTO zips_required
SELECT to_char(10000 + 100 * ROWNUM) FROM dual CONNECT BY LEVEL <= 5;
INSERT INTO zips_available
(SELECT to_number(zip) + 10 * r, 100 - 10 * r FROM zips_required, (SELECT ROWNUM r FROM dual CONNECT BY LEVEL <= 9));
CREATE OR REPLACE FUNCTION zipdistance(zipfrom VARCHAR2,zipto VARCHAR2) RETURN NUMBER IS
BEGIN
RETURN abs(to_number(zipfrom) - to_number(zipto));
END zipdistance;
/
ملحوظة: لقد استخدمت COUNT(locations) وSUM(locations) في سؤالك، وافترضت أنه COUNT(locations)
نصائح أخرى
SELECT *
FROM (
SELECT zip, zd, ROW_NUMBER() OVER (PARTITION BY zip ORDER BY rn DESC) AS rn2
FROM (
SELECT zip, zd, ROW_NUMBER() OVER (PARTITION BY zip ORDER BY zd DESC) AS rn
FROM (
SELECT zr.zip, zipdistance(zr.zip, za.zip) AS zd
FROM zips_required zr
JOIN zips_available za
)
)
WHERE rn <= n
)
WHERE rn2 = 1
لكل zip_required
، وهذا سوف تحديد المسافة الحد الأدنى إلى التي تناسب في N
zip_available
، أو المسافة القصوى إذا كان عدد zip_available
هو أقل من N
.
وأنا حل نفس المشكلة عن طريق إنشاء مجموعة فرعية من ZIP داخل دائرة نصف قطرها متر مربع من الرمز البريدي معين (سهلة الرياضيات: <أو> بذور النيم نصف القطر)، ثم بالتكرار عبر كل دخول في فرعية لمعرفة ما إذا كان داخل دائرة نصف قطرها اللازمة . عملت مثل سحر وكان سريع جدا.
كانت لدي متطلبات مماثلة جزئيًا في أحد مشاريعي القديمة ...لحساب المسافة بين 2 الرمز البريدي في الولايات المتحدة.ولحل هذه المشكلة، كنت قد استفدت بشكل كبير من البيانات المكانية الأمريكية.كان النهج الأساسي هو الحصول على الرمز البريدي المصدر (خط العرض وخط الطول) والرمز البريدي للوجهة (خط العرض وخط الطول).الآن قمت بتطبيق دالة للحصول على المسافة بناءً على ما ورد أعلاه.الصيغة الأساسية التي تساعد في إجراء هذا الحساب متاحة في الموقع التاليلقد قمت أيضًا بالتحقق من صحة النتيجة من خلال الإشارة إلى هذا الموقع...
ملحوظة:ومع ذلك، سيوفر هذا مسافات تقريبية، لذلك يمكن للمرء استخدام هذا وفقًا لذلك.بمجرد إنشاء الفوائد بسرعة فائقة لجلب النتائج.