كيفية تمرير قائمة مفصولة بفواصل إلى إجراء مخزن؟

StackOverflow https://stackoverflow.com/questions/6369

  •  08-06-2019
  •  | 
  •  

سؤال

لذلك لدي عملية مخزنة في Sybase تأخذ معلمة واحدة وهي عبارة عن قائمة سلاسل مفصولة بفواصل وتقوم بتشغيل استعلام في جملة IN():

CREATE PROCEDURE getSomething @keyList varchar(4096)
AS
SELECT * FROM mytbl WHERE name IN (@keyList)

كيف يمكنني استدعاء العملية المخزنة الخاصة بي والتي تحتوي على أكثر من قيمة واحدة في القائمة؟لقد حاولت حتى الآن

exec getSomething 'John'         -- works but only 1 value
exec getSomething 'John','Tom'   -- doesn't work - expects two variables
exec getSomething "'John','Tom'" -- doesn't work - doesn't find anything
exec getSomething '"John","Tom"' -- doesn't work - doesn't find anything
exec getSomething '\'John\',\'Tom\'' -- doesn't work - syntax error

يحرر: لقد وجدت هذا فعلا صفحة يحتوي على مرجع رائع للطرق المختلفة لتمرير مصفوفة إلى sproc

هل كانت مفيدة؟

المحلول

إذا كنت تستخدم Sybase 12.5 أو إصدارًا أقدم، فلن تتمكن من استخدام الوظائف.قد يكون الحل البديل هو ملء جدول مؤقت بالقيم وقراءتها من هناك.

نصائح أخرى

لقد تأخر هذا قليلًا، ولكن واجهت هذه المشكلة بالتحديد منذ فترة ووجدت حلاً.

الحيلة هي الاقتباس المزدوج ثم لف السلسلة بأكملها بين علامتي اقتباس.

exec getSomething """John"",""Tom"",""Bob"",""Harry"""

قم بتعديل proc الخاص بك لمطابقة إدخال الجدول مع السلسلة.

CREATE PROCEDURE getSomething @keyList varchar(4096)
AS
SELECT * FROM mytbl WHERE @keyList LIKE '%'+name+'%' 

لقد قمت بهذا في الإنتاج منذ ASE 12.5؛نحن الآن على 15.0.3.

قم بتمرير القائمة المفصولة بفواصل إلى دالة تُرجع قيمة جدول.يوجد مثال MS SQL في مكان ما على StackOverflow، اللعنة إذا كان بإمكاني رؤيته في الوقت الحالي.

CREATE PROCEDURE getSomething @keyList varchar(4096)
AS
SELECT * FROM mytbl WHERE name IN (fn_GetKeyList(@keyList))

الاتصال مع -

exec getSomething 'John,Tom,Foo,Bar'

أعتقد أن Sybase يجب أن يكون قادرًا على القيام بشيء مماثل؟

هل تحتاج إلى استخدام قائمة مفصولة بفواصل؟في العامين الماضيين، كنت أتبنى هذا النوع من الأفكار وأقوم بتمرير ملف XML.تأخذ "وظيفة" openxml سلسلة وتجعلها مثل XML، ثم إذا قمت بإنشاء جدول مؤقت مع البيانات، فهو قابل للاستعلام.

DECLARE @idoc int
DECLARE @doc varchar(1000)
SET @doc ='
<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot">
   <Order CustomerID="VINET" EmployeeID="5" OrderDate="1996-07-04T00:00:00">
      <OrderDetail OrderID="10248" ProductID="11" Quantity="12"/>
      <OrderDetail OrderID="10248" ProductID="42" Quantity="10"/>
   </Order>
</Customer>
<Customer CustomerID="LILAS" ContactName="Carlos Gonzlez">
   <Order CustomerID="LILAS" EmployeeID="3" OrderDate="1996-08-16T00:00:00">
      <OrderDetail OrderID="10283" ProductID="72" Quantity="3"/>
   </Order>
</Customer>
</ROOT>'
--Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT statement that uses the OPENXML rowset provider.
SELECT    *
FROM       OPENXML (@idoc, '/ROOT/Customer',1)
            WITH (CustomerID  varchar(10),
                  ContactName varchar(20))

فيما يتعلق بفكرة كيفن المتمثلة في تمرير المعلمة إلى دالة تقسم النص إلى جدول، فإليك تطبيقي لهذه الوظيفة منذ بضع سنوات مضت.يعمل علاجا.

تقسيم النص إلى كلمات في SQL

هذه طريقة سريعة وقذرة قد تكون مفيدة:

select  * 
from    mytbl 
where   "," + ltrim(rtrim(@keylist)) + "," like "%," + ltrim(rtrim(name)) + ",%"

لست متأكدًا مما إذا كان موجودًا في ASE، ولكن في SQL Anywhere، فإن ملف sa_split_list تقوم الدالة بإرجاع جدول من ملف CSV.يحتوي على وسائط اختيارية لتمرير محدد مختلف (الافتراضي هو فاصلة) وطول أقصى لكل قيمة تم إرجاعها.

وظيفة sa_split_list

مشكلة المكالمات مثل هذا:exec getSomething ''"John"،"Tom"' هو أنه يتعامل مع ""John"،"Tom"" كسلسلة واحدة، وسوف يطابق فقط الإدخال في الجدول الذي هو ""John"،"Tom"".

إذا كنت لا ترغب في استخدام جدول مؤقت كما في إجابة بول، فيمكنك استخدام SQL الديناميكي.(بافتراض الإصدار 12+)

CREATE PROCEDURE getSomething @keyList varchar(4096)
AS
declare @sql varchar(4096)
select @sql = "SELECT * FROM mytbl WHERE name IN (" + @keyList +")"
exec(@sql)

ستحتاج إلى التأكد من أن العناصر الموجودة في @keylist تحتوي على علامات اقتباس حولها، حتى لو كانت قيمًا فردية.

للتطرق إلى ما قدمه @Abel، ما ساعدني هو:

كان غرضي هو أخذ ما تم إدخاله من قبل المستخدم النهائي من SSRs واستخدامه في My Where Phense كـ (SELECT) بشكل واضح @icd_value_rpt سيتم التعليق في استعلام مجموعة البيانات الخاصة بي.

DECLARE @ICD_VALUE_RPT VARCHAR(MAX) SET @ICD_VALUE_RPT = 'Value1, Value2'
DECLARE @ICD_VALUE_ARRAY XML SET @ICD_VALUE_ARRAY = CONCAT('<id>', REPLACE(REPLACE(@ICD_VALUE_RPT, ',', '</id>,<id>'),' ',''), '</id>')

ثم في بلدي WHERE أضفت:

(PATS_WITH_PL_DIAGS.ICD10_CODE IN (SELECT ParamValues.ID.value('.','VARCHAR(MAX)') FROM @ICD_VALUE_ARRAY.nodes('id') AS ParamValues(ID))
OR PATS_WITH_PL_DIAGS.ICD9_CODE IN (SELECT ParamValues.ID.value('.','VARCHAR(MAX)') FROM @ICD_VALUE_ARRAY.nodes('id') AS ParamValues(ID))
)

جرب هذه الطريقة.إنه يعمل بالنسبة لي.

@itemIds varchar(max)

CREATE PROCEDURE getSomething @keyList varchar(4096)
AS
SELECT * FROM mytbl WHERE name IN (SELECT Value FROM [Global_Split] (@itemIds,','))

هذا يعمل في SQL.أعلن في الخاص GetSomething إجراء متغير من النوع XML على هذا النحو:

DECLARE @NameArray XML = NULL

ينفذ نص الإجراء المخزن ما يلي:

SELECT * FROM MyTbl WHERE name IN (SELECT ParamValues.ID.value('.','VARCHAR(10)')
FROM @NameArray.nodes('id') AS ParamValues(ID))

من داخل كود SQL الذي يستدعي SP للإعلان عن متغير XML وتهيئته قبل استدعاء الإجراء المخزن:

DECLARE @NameArray XML

SET @NameArray = '<id><</id>id>Name_1<<id>/id></id><id><</id>id>Name_2<<id>/id></id><id><</id>id>Name_3<<id>/id></id><id><</id>id>Name_4<<id>/id></id>'

باستخدام المثال الخاص بك فإن استدعاء الإجراء المخزن سيكون:

EXEC GetSomething @NameArray

لقد استخدمت هذه الطريقة من قبل وهي تعمل بشكل جيد.إذا كنت تريد اختبارًا سريعًا، فانسخ الكود التالي والصقه في استعلام جديد وقم بتنفيذه:

DECLARE @IdArray XML

SET @IdArray = '<id><</id>id>Name_1<<id>/id></id><id><</id>id>Name_2<<id>/id></id><id><</id>id>Name_3<<id>/id></id><id><</id>id>Name_4<<id>/id></id>'

SELECT ParamValues.ID.value('.','VARCHAR(10)')
FROM @IdArray.nodes('id') AS ParamValues(ID)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top