لا يتطابق الحرفي إلى سلسلة التنسيق لـ Oracle SQL to_date على عمود سلسلة
سؤال
عزيزي SQL Gurus من Stack Overflow:
بيئة: وحي
أحاول أن أفهم لماذا لا يمكنني القيام باختيار to_date على عمود جدول يحتوي على سلاسل. لاحظ أن Tablez مع عمود من قيمة الاسم في المثال أدناه يحتوي على مجموعة من الأوتار ، بعضها هو التنسيق الصحيح ، على سبيل المثال 6/20/2010 00:00:00.
Tablez
| Value |
| __________________ |
| 6/21/2010 00:00:00 |
| Somestring |
| Some Other strings |
| 6/21/2010 00:00:00 |
| 6/22/2010 00:00:00 |
الأعمال التالية
SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM tableX a, tableY b, tableZ c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.other_id
AND b.id = c.new_id
هذا يعيد شيئًا مثل (وهو أمر جيد):
| somedate |
| __________________ |
| 21.06.2010 00:00:00 |
| 21.06.2010 00:00:00 |
| 22.06.2010 00:00:00 |
ما يلي لا يعمل
SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM properties$aud a, template_properties$aud b, consumable_properties$aud c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.property_id
AND b.id = c.template_property_id
AND To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
يعود مع:
ORA-01861: لا يتطابق الحرفي
ماذا أفتقد هنا؟ مجرد ملاحظة سريعة:
...
AND b.id = c.template_property_id
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
لا يعمل أيضًا.
شكرًا!!
هدف لتكون قادرًا على القيام بتاريخ بين الاستفسارات على C.Value من أجل تحديد نطاقات التاريخ.
المحلول
ترتيب أن أوراكل يقيم الشروط الموجودة في الفقرة التي لا يتم إصلاحها. وهذا يعني أنه يمكن أن تختار تقييم الحالة التي تحتوي على to_date قبل المعايير الأخرى ، وفي هذه الحالة سيفشل الاستعلام. لمنع ذلك ، أضف تلميح ordered_predicates إلى استعلامك ، ولكن كن على علم بأن هذا قد يتطلب ضبطًا يدويًا إضافيًا لتحسين الأداء.
SELECT /*+ ordered_predicates */
To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM properties$aud a,
template_properties$aud b,
consumable_properties$aud c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.property_id
AND b.id = c.template_property_id
AND To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
فيما يبدو ordered_predicates
تم إهماله بدءًا من 10g. في هذه الحالة ، أعتقد أن خيارك الوحيد هو استخدام مسابقة فرعية بطريقة تضطر إلى التقييم لتقييمه أولاً (أي أنه لا يمكن الجمع بين الاستعلامات). أسهل طريقة للقيام بذلك هي وضعها rownum
في بيان الاستعلام الداخلي.
SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM (SELECT value
FROM properties$aud a,
template_properties$aud b,
consumable_properties$aud c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.property_id
AND b.id = c.template_property_id
AND rownum > 0)
WHERE To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
نصائح أخرى
create or replace function to_date_or_null(v_str_date in varchar2
, v_str_fmt in varchar2 default null) return date as
begin
if v_str_fmt is null then
return to_date(v_str_date);
else
return to_date(v_str_date, v_str_fmt);
end if;
exception
when others then
return null;
end to_date_or_null;
/
اختبارات:
SQL> select to_date_or_null('2000-01-01', 'YYYY-MM-DD') from dual -- Valid;
TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00
SQL> select to_date_or_null('Not a date at all') from dual -- Not Valid;
TO_DATE_OR_NULL('NO
-------------------
SQL> select to_date_or_null('2000-01-01') from dual -- Valid matches my NLS settings;
TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00
SQL> select to_date_or_null('01-Jan-00') from dual -- Does not match my NLS settings;
TO_DATE_OR_NULL('01
-------------------
هناك تقنية أخرى تضم التحويل في حالة ما. فمثلا
SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)
هذا يصبح سريعًا حقًا عندما تكون الجمل معقدة.
هل تريد التحقق مما إذا كان C.Value تنسيقًا صالحًا مع
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
؟ لن ينجح هذا ، ستحتاج إلى إجراء الشيك بطريقة أخرى. يمكنك استخدام تعبير منتظم (أعتقد ، لا تستخدمه منذ فترة). الأفضل من ذلك إذا كان نموذج البيانات الخاص بك سيسمح لك بتمييز الصفوف المعنية.