SQL IN වගන්තියක් පරාමිතිකරණය කරන්න


1047

INමේ හා සමාන විචල්‍ය තර්ක සංඛ්‍යාවක් සහිත වගන්තියක් අඩංගු විමසුමක් පරාමිතිකරණය කරන්නේ කෙසේද ?

SELECT * FROM Tags 
WHERE Name IN ('ruby','rails','scruffy','rubyonrails')
ORDER BY Count DESC

මෙම විමසුමේදී, තර්ක ගණන 1 සිට 5 දක්වා ඕනෑම තැනක විය හැකිය.

මේ සඳහා (හෝ එක්ස්එම්එල්) විශේෂිත ගබඩා ක්‍රමවේදයක් භාවිතා නොකිරීමට මම කැමැත්තෙමි, නමුත් SQL සේවාදායක 2008 සඳහා විශේෂිත වූ අලංකාර ක්‍රමයක් තිබේ නම් , මම ඒ සඳහා විවෘතව සිටිමි.



Answers:


317

මෙන්න මම භාවිතා කළ ඉක්මන් හා අපිරිසිදු තාක්ෂණය:

SELECT * FROM Tags
WHERE '|ruby|rails|scruffy|rubyonrails|'
LIKE '%|' + Name + '|%'

ඉතින් මෙන්න C # කේතය:

string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" };
const string cmdText = "select * from tags where '|' + @tags + '|' like '%|' + Name + '|%'";

using (SqlCommand cmd = new SqlCommand(cmdText)) {
   cmd.Parameters.AddWithValue("@tags", string.Join("|", tags);
}

අවවාද දෙකක්:

  • කාර්ය සාධනය දරුණුයි. LIKE "%...%"විමසුම් සුචිගත කර නොමැත.
  • ඔබට |හිස්, හිස් හෝ ශුන්‍ය ටැග් නොමැති බවට වග බලා ගන්න හෝ මෙය ක්‍රියා නොකරනු ඇත

මෙය සාක්ෂාත් කර ගැනීම සඳහා වෙනත් ක්‍රම තිබේ, සමහර අය පිරිසිදු යැයි සලකනු ඇත, එබැවින් කරුණාකර දිගටම කියවන්න.


122
එය හෙලා මන්දගාමී වනු ඇත
මැට් රොගිෂ්

14
ඔව්, මෙය මේස පරිලෝකනයකි. පේළි 10 ක් සඳහා විශිෂ්ටයි, 100,000 ක් සඳහා කම්මැලි ය.
විල් හාර්තුං

17
ටැග් වල පයිප්ප ඇති බව පරීක්ෂා කිරීමට වග බලා ගන්න.
ජොයෙල් කොහූර්න්

18
මෙය ප්‍රශ්නයට පවා පිළිතුරු සපයන්නේ නැත. ඇත්ත වශයෙන්ම, පරාමිතීන් එකතු කරන්නේ කොතැනදැයි බැලීම පහසුය, නමුත් විමසුම පරාමිතිකරණය කිරීමට පවා කරදර නොවන්නේ නම් මෙය විසඳුමක් ලෙස පිළිගන්නේ කෙසේද? එය පරාමිතිගත නොවන නිසා එය ark මාක් බ්‍රැකට්ට වඩා සරල බව පෙනේ.
tvanfosson

22
ඔබේ ටැගය 'රූබි | රේල් පීලි' නම් කුමක් කළ යුතුද? එය ගැලපෙනු ඇත, එය වැරදිය. ඔබ එවැනි විසඳුම් සකස් කරන විට, ටැග් වල පයිප්ප අඩංගු නොවන බවට වග බලා ගත යුතුය, නැතහොත් ඒවා පැහැදිලිව පෙරහන් කරන්න: ටැග් වලින් * තෝරන්න '| රුබී | රේල් පීලි | සීරීම් | රුබියොන්රේල්ස් |' '% |' වැනි + නම + '|%' සහ නම '%!%' වැනි නොවේ
AK

733

ඔබට එක් එක් අගය පරාමිතිකරණය කළ හැකිය , එබැවින් මෙවැනි දෙයක්:

string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" };
string cmdText = "SELECT * FROM Tags WHERE Name IN ({0})";

string[] paramNames = tags.Select(
    (s, i) => "@tag" + i.ToString()
).ToArray();

string inClause = string.Join(", ", paramNames);
using (SqlCommand cmd = new SqlCommand(string.Format(cmdText, inClause))) {
    for(int i = 0; i < paramNames.Length; i++) {
       cmd.Parameters.AddWithValue(paramNames[i], tags[i]);
    }
}

එය ඔබට ලබා දෙනු ඇත:

cmd.CommandText = "SELECT * FROM Tags WHERE Name IN (@tag0, @tag1, @tag2, @tag3)"
cmd.Parameters["@tag0"] = "ruby"
cmd.Parameters["@tag1"] = "rails"
cmd.Parameters["@tag2"] = "scruffy"
cmd.Parameters["@tag3"] = "rubyonrails"

නැත, මෙය SQL එන්නත් කිරීම සඳහා විවෘත නොවේ . CommandText වෙත එන්නත් කරන ලද එකම පෙළ පරිශීලක ආදානය මත පදනම් නොවේ. එය තනිකරම පදනම් වී ඇත්තේ දෘඩ කේත කරන ලද "ටැග්" උපසර්ගය සහ අරාවෙහි දර්ශකය මත ය. දර්ශකය සැමවිටම පූර්ණ සංඛ්‍යාවක් වනු ඇත, පරිශීලකයා ජනනය නොකරන අතර ආරක්ෂිත වේ.

පරිශීලක ආදාන අගයන් තවමත් පරාමිතීන් තුළට පුරවා ඇති බැවින් එහි කිසිදු අවදානමක් නොමැත.

සංස්කරණය කරන්න:

එන්නත් කිරීමේ ගැටළු පසෙකට දමා, විචල්‍ය පරාමිති ගණනකට (ඉහත පරිදි) අනුගත වීමට විධාන පා text ය සෑදීම, හැඹිලි විමසුම් වලින් ප්‍රයෝජන ගැනීමට SQL සේවාදායකයට ඇති හැකියාව බාධා කරන බව සැලකිල්ලට ගන්න. ශුද්ධ ප්‍රති result ලය නම්, පරාමිතීන් භාවිතා කිරීමේ වටිනාකම ඔබට මුලින් ම පාහේ අහිමි වීමයි (හුදෙක් පුරෝකථනය කරන ලද නූල් SQL තුළට ඇතුළු කිරීමට වඩා වෙනස්ව).

හැඹිලි විමසුම් සැලසුම් වටිනාකමක් නැති බව නොවේ, නමුත් IMO මෙම විමසුම එයින් වැඩි ප්‍රතිලාභයක් ලබා ගැනීමට තරම් සංකීර්ණ නොවේ. සම්පාදන පිරිවැය ක්‍රියාත්මක කිරීමේ පිරිවැය කරා ළඟා විය හැකිය (හෝ ඉක්මවා යා හැක), ඔබ තවමත් කතා කරන්නේ මිලි තත්පර.

ඔබට ප්‍රමාණවත් තරම් RAM ප්‍රමාණයක් තිබේ නම්, SQL සේවාදායකය පොදු පරාමිතීන් ගණනය කිරීම සඳහා සැලැස්මක් රඳවා ගනු ඇතැයි මම බලාපොරොත්තු වෙමි. ඔබට සැමවිටම පරාමිති පහක් එකතු කළ හැකි යැයි මම සිතමි, සහ නිශ්චිතව දක්වා නොමැති ටැග් NULL වීමට ඉඩ දෙන්න - විමසුම් සැලැස්ම එක හා සමාන විය යුතුය, නමුත් එය මට ඉතා කැත ලෙස පෙනේ, එය ක්ෂුද්‍ර ප්‍රශස්තිකරණයට සුදුසු යැයි මට විශ්වාස නැත (කෙසේ වෙතත්, තොග පිටාර ගැලීම මත - එය ඉතා වටිනවා විය හැකිය).

එසේම, SQL සේවාදායකය 7 සහ පසුව විමසුම් ස්වයංක්‍රීයව පරාමිතිකරණය කරනු ඇත , එබැවින් කාර්ය සාධන දෘෂ්ටි කෝණයකින් පරාමිතීන් භාවිතා කිරීම සැබවින්ම අවශ්‍ය නොවේ - කෙසේ වෙතත් එය ආරක්ෂක දෘෂ්ටි කෝණයකින් තීරණාත්මක වේ - විශේෂයෙන් පරිශීලක ආදාන දත්ත සමඟ.


2
මූලික වශයෙන් “ආශ්‍රිත” ප්‍රශ්නයට මගේ පිළිතුරට සමාන වන අතර පැහැදිලිවම හොඳම විසඳුම එය අර්ථ නිරූපණයට වඩා ruc ලදායී හා කාර්යක්ෂම බැවින් (වඩා දුෂ්කර).
tvanfosson

49
LINQ to SQL එය කරන්නේ එලෙසයි, BTW
Mark Cidade

3
Ure පිරිසිදු: මෙහි සමස්ත කරුණ වන්නේ ඔබ ගතික SQL භාවිතා කළහොත් ඔබට අවදානමට ලක්විය හැකි SQL එන්නත් කිරීමයි.
රේ

2
එන්නත් කිරීමේ ගැටළු පසෙකට දමා, විචල්ය පරාමිති ගණනකට (ඉහත පරිදි) අනුගත වීමට විධාන පෙළ තැනීම, හැඹිලි විමසුම් වලින් වාසි ලබා ගැනීමට SQL සේවාදායකයට ඇති හැකියාව බාධා කරන බව සැලකිල්ලට ගන්න. ශුද්ධ ප්‍රති result ලය නම්, ඔබ විසින් පරාමිතීන් භාවිතා කිරීමේ වටිනාකම මුලින් ම පාහේ ලිහිල් කිරීමයි (හුදෙක් පුරෝකථන නූල් SQL තුළට ඇතුළු කිරීමට වඩා වෙනස්ව).
මාර්ක්

4
දත්ත ගොඩ් - ඔව්, ඔබට ටැග් 2100 කට වඩා අවශ්‍ය නම් ඔබට වෙනත් විසඳුමක් අවශ්‍ය යැයි මම සිතමි. නමුත් බාසාර්බ් වෙත ළඟා විය හැක්කේ සාමාන්‍ය ටැග් දිග <අක්ෂර 3 ක් නම් පමණි (ඔබට පරිසීමකයද අවශ්‍ය බැවින්). msdn.microsoft.com/en-us/library/ms143432.aspx
මාර්ක් බ්‍රැකට්

250

SQL Server 2008 සඳහා, ඔබට වගු වටිනාකමින් යුත් පරාමිතියක් භාවිතා කළ හැකිය . එය ටිකක් වැඩකි, නමුත් එය මගේ අනෙක් ක්‍රමයට වඩා පිරිසිදු ය .

පළමුව, ඔබ වර්ගයක් නිර්මාණය කළ යුතුය

CREATE TYPE dbo.TagNamesTableType AS TABLE ( Name nvarchar(50) )

එවිට, ඔබගේ ADO.NET කේතය මේ ආකාරයට පෙනේ:

string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" };
cmd.CommandText = "SELECT Tags.* FROM Tags JOIN @tagNames as P ON Tags.Name = P.Name";

// value must be IEnumerable<SqlDataRecord>
cmd.Parameters.AddWithValue("@tagNames", tags.AsSqlDataRecord("Name")).SqlDbType = SqlDbType.Structured;
cmd.Parameters["@tagNames"].TypeName = "dbo.TagNamesTableType";

// Extension method for converting IEnumerable<string> to IEnumerable<SqlDataRecord>
public static IEnumerable<SqlDataRecord> AsSqlDataRecord(this IEnumerable<string> values, string columnName) {
    if (values == null || !values.Any()) return null; // Annoying, but SqlClient wants null instead of 0 rows
    var firstRecord = values.First();
    var metadata= new SqlMetaData(columnName, SqlDbType.NVarChar, 50); //50 as per SQL Type
    return values.Select(v => 
    {
       var r = new SqlDataRecord(metadata);
       r.SetValues(v);
       return r;
    });
}

Og ඩග් අනුව යාවත්කාලීන කරන්න

කරුණාකර වළක්වා ගැනීමට උත්සාහ කරන්න var metadata = SqlMetaData.InferFromValue(firstRecord, columnName);

එය පළමු අගය දිග ලෙස සකසා ඇත, එබැවින් පළමු අගය අක්ෂර 3 ක් නම් එහි උපරිම දිග 3 සහ අනෙකුත් වාර්තා අකුරු 3 ක් නම් කපා දමනු ඇත.

එබැවින්, භාවිතා කිරීමට උත්සාහ කරන්න: var metadata= new SqlMetaData(columnName, SqlDbType.NVarChar, maxLen);

සටහන: -1උපරිම දිග සඳහා.


41
අපි මෙය පරීක්‍ෂා කළ අතර වගු අගය කළ පරාමිතීන් DOG මන්දගාමී වේ. එක් ටීවීපී එකකට වඩා විමසුම් 5 ක් ක්‍රියාත්මක කිරීම වචනාර්ථයෙන් වේගවත් ය.
ජෙෆ් ඇට්වුඩ්

4
E ජෙෆ් ඇට්වුඩ් - ඔබ විමසුම නැවත වෙනස් කිරීමට උත්සාහ කර තිබේද SELECT * FROM tags WHERE tags.name IN (SELECT name from @tvp);? න්‍යාය අනුව, මෙය සැබවින්ම වේගවත්ම ප්‍රවේශය විය යුතුය. ඔබට අදාළ දර්ශක භාවිතා කළ හැකිය (උදා: ටැග් නාමයේ දර්ශකය INCLUDEගණනය කිරීම වඩාත් සුදුසු වේ), සහ SQL සේවාදායකය විසින් සියලුම ටැග් සහ ඒවායේ ගණන් ලබා ගැනීමට උත්සාහ කළ යුතුය. සැලැස්ම මොන වගේද?
නික් චම්මාස්

9
මම මෙයද පරීක්‍ෂා කර ඇති අතර එය වේගයෙන් ආලෝකමත් වේ (විශාල IN නූලක් සෑදීමට සාපේක්ෂව). "පරාමිති අගය Int32 [] සිට IEnumerable`1 බවට පරිවර්තනය කිරීමට අපොහොසත් වූ බැවින් පරාමිතිය සැකසීමේදී මට යම් ගැටලු ඇති විය." කෙසේ වෙතත්, එය විසඳා මෙන්න මම සාම්පලයක් pastebin.com/qHP05CXc
ෆ්‍රෙඩ්රික් ජොහැන්සන්

6
Red ෆ්‍රෙඩ්රික් ජොහැන්සන් - උඩුකුරු 130 න්, මෙය ක්‍රියාත්මක කිරීමට උත්සාහ කළ එකම ධාවන පථය ඔබ විය හැකිය! මම ලියකියවිලි කියවීමේදී වැරැද්දක් කර ඇති අතර ඔබට ඇත්ත වශයෙන්ම අවශ්‍ය වන්නේ IEnumerable <SqlDataRecord> මිස කිසිදු IEnumerable නොවේ. කේතය යාවත්කාලීන කර ඇත.
මාර්ක් බ්‍රැකට්

3
Ark මාක්බ්‍රැකට් යාවත්කාලීන කිරීමක් සමඟ විශිෂ්ටයි! මම ලුසීන් සෙවුම් දර්ශකයක් විමසන බැවින් මෙම කේතය ඇත්තෙන්ම මට දවස ඉතිරි කර ඇති අතර එය සමහර විට SQL සේවාදායකයට එරෙහිව දෙවරක් පරීක්ෂා කළ යුතු පහර 50.000 ක් හෝ ඊට වැඩි ප්‍රමාණයක් ලබා දෙයි - එබැවින් මම int [] (ලේඛනය / SQL යතුරු) ඉන්පසු ඉහත කේතය පැමිණේ. මුළු OP දැන් මීටර් 200 ට වඩා අඩු වේ :)
ෆ්‍රෙඩ්රික් ජොහැන්සන්

190

මුල් ප්‍රශ්නය වූයේ "විමසුමක් පරාමිතිකරණය කරන්නේ කෙසේද ..."

මෙය මුල් ප්‍රශ්නයට පිළිතුරක් නොවන බව මෙහි සඳහන් කිරීමට මට ඉඩ දෙන්න . වෙනත් හොඳ පිළිතුරු වල දැනටමත් ඒ පිළිබඳ නිරූපණ කිහිපයක් තිබේ.

ඒ සමඟම, ඉදිරියට ගොස් මෙම පිළිතුර සලකුණු කරන්න, එය පහත් කරන්න, එය පිළිතුරක් නොවන ලෙස සලකුණු කරන්න ... ඔබ හරි යැයි විශ්වාස කරන ඕනෑම දෙයක් කරන්න.

මා (සහ තවත් 231) ඉහළට ඔසවා තැබීමට කැමති පිළිතුර සඳහා මාර්ක් බ්‍රැකට්ගේ පිළිතුර බලන්න. ඔහුගේ පිළිතුරෙහි දක්වා ඇති ප්‍රවේශය 1) බන්ධන විචල්‍යයන් effective ලදායී ලෙස භාවිතා කිරීමට සහ 2) උපහාසාත්මක අනාවැකි සඳහා ඉඩ ලබා දේ.

තෝරාගත් පිළිතුර

මට මෙහි ආමන්ත්‍රණය කිරීමට අවශ්‍ය වන්නේ ජොයෙල් ස්පොල්ස්කිගේ පිළිතුරෙහි දක්වා ඇති ප්‍රවේශයයි, නිවැරදි පිළිතුර ලෙස “තෝරාගත්” පිළිතුරයි.

ජොයෙල් ස්පොල්ස්කිගේ ප්‍රවේශය දක්ෂයි. එය සාධාරණ ලෙස ක්‍රියාත්මක වන අතර, එය “සාමාන්‍ය” අගයන් ලබා දී ඇති අතර, NULL සහ හිස් නූල වැනි ප්‍රමිතිගත දාර සමඟ. විශේෂිත යෙදුමක් සඳහා එය ප්‍රමාණවත් විය හැකිය.

නමුත් මෙම ප්‍රවේශය සාමාන්‍යකරණය කිරීමේදී, Nameතීරුවේ ආදේශක අක්‍ෂරයක් අඩංගු වන විට (LIKE අනාවැකි මගින් හඳුනාගෙන ඇති පරිදි) වඩාත් අපැහැදිලි කොන අවස්ථා ද සලකා බලමු . මම බහුලව භාවිතා කරන වයිල්ඩ්කාඩ් චරිතය %(ප්‍රතිශත ලකුණකි.). ඒ නිසා අපි දැන් මෙහි ගනුදෙනු කරමු, පසුව වෙනත් අවස්ථාවන්ට යමු.

% අක්ෂර සමඟ සමහර ගැටලු

හි නම අගය සලකා බලන්න 'pe%ter'. (මෙහි ඇති උදාහරණ සඳහා, මම තීරු නම වෙනුවට වචනාර්ථයෙන් නූල් අගයක් භාවිතා කරමි.) පෝරමයේ විමසුමකින් `'pe% ter' හි නම අගයක් සහිත පේළියක් ආපසු ලබා දෙනු ඇත:

select ...
 where '|peanut|butter|' like '%|' + 'pe%ter' + '|%'

සෙවුම් පදවල අනුපිළිවෙල ආපසු හරවනු ලැබුවහොත් එම පේළියම ආපසු නොලැබේ :

select ...
 where '|butter|peanut|' like '%|' + 'pe%ter' + '|%'

අප නිරීක්ෂණය කරන හැසිරීම අමුතුයි. ලැයිස්තුවේ ඇති සෙවුම් පදවල අනුපිළිවෙල වෙනස් කිරීම ප්‍රති result ල කට්ටලය වෙනස් කරයි.

pe%terඔහු කොතරම් කැමති වුවත් රටකජු බටර් ගැලපීමට අපට අවශ්‍ය නොවනු ඇතැයි නොකියයි.

අපැහැදිලි කොන නඩුව

. මගේ අත්දැකීම් අනුව, LIKEසංසන්දනාත්මක ක්‍රියාකරුවෙකුගේ දකුණු පැත්තේ ආදේශක කාඩ්පත් ලෙස සලකනු ලබන අක්ෂර හෝ රටා විශේෂයෙන් තහනම් කර ඇති දත්ත සමුදා බාධකයක් මම කලාතුරකින් දැක ඇත්තෙමි .

සිදුරක් ඇල්ලීම

මෙම සිදුර ඇලවීම සඳහා එක් ප්‍රවේශයක් වන්නේ %ආදේශක චරිතයෙන් ගැලවීමයි. (ක්‍රියාකරුගේ පැන යාමේ වගන්තිය ගැන නොදන්නා ඕනෑම කෙනෙකුට, මෙන්න SQL සේවාදායක ප්‍රලේඛනයට සබැඳියක් .

select ...
 where '|peanut|butter|'
  like '%|' + 'pe\%ter' + '|%' escape '\'

දැන් අපට වචනයේ පරිසමාප්ත අර්ථයෙන්ම ගැලපේ. ඇත්ත වශයෙන්ම, අපට තීරු නමක් ඇති විට, අපට ආදේශක කාඩ්පතෙන් ගතිකව ගැලවීමට අවශ්‍ය වනු ඇත. අපට REPLACEශ්‍රිතය භාවිතා කර %චරිතයේ සිදුවීම් සොයා ගැනීමටත් , එක් එක් කෙනා ඉදිරිපිට බැක්ස්ලෑෂ් අක්ෂරයක් ඇතුළත් කිරීමටත් හැකිය:

select ...
 where '|pe%ter|'
  like '%|' + REPLACE( 'pe%ter' ,'%','\%') + '|%' escape '\'

එබැවින්% ආදේශක කාඩ්පත සමඟ ගැටළුව විසඳයි. පාහේ.

පැන යාමෙන් බේරෙන්න

අපගේ විසඳුම තවත් ගැටලුවක් හඳුන්වා දී ඇති බව අපි හඳුනා ගනිමු. ගැලවීමේ චරිතය. ගැලවීමේ චරිතයේ ඕනෑම සිදුවීමකින් මිදීමට අපට අවශ්‍ය වනු ඇති බව අපට පෙනේ. මෙවර අපි භාවිතා කරන්නේ! ගැලවීමේ චරිතය ලෙස:

select ...
 where '|pe%t!r|'
  like '%|' + REPLACE(REPLACE( 'pe%t!r' ,'!','!!'),'%','!%') + '|%' escape '!'

අවධාරනය ද වේ

දැන් අපි රෝල් කර ඇති නිසා, අපට REPLACEඅවධාරනය කළ හැකි ආදේශක කාඩ්පත තවත් හසුරුව එකතු කළ හැකිය . විනෝදය සඳහා, මේ වතාවේ, අපි ගැලවීමේ චරිතය ලෙස භාවිතා කරමු.

select ...
 where '|p_%t!r|'
  like '%|' + REPLACE(REPLACE(REPLACE( 'p_%t!r' ,'$','$$'),'%','$%'),'_','$_') + '|%' escape '$'

පැන යාමට මම මෙම ප්‍රවේශයට වැඩි කැමැත්තක් දක්වන්නේ එය ඔරකල් සහ MySQL මෙන්ම SQL සේවාදායකයේ ක්‍රියාත්මක වන බැවිනි. (මම සාමාන්‍යයෙන් \ බැක්ස්ලෑෂ් ගැලවීමේ චරිතය ලෙස භාවිතා කරමි, මන්ද එය අප නිරන්තර ප්‍රකාශනවල භාවිතා කරන චරිතයයි. නමුත් සම්මුතියෙන් එය සීමා කරන්නේ ඇයි!

ඒ කරදරකාරී වරහන්

වයිල්ඩ්කාඩ් අක්ෂර වරහන් තුළට කොටු කිරීමෙන් වචනාර්ථයන් ලෙස සැලකීමට SQL සේවාදායකය ඉඩ දෙයි []. එබැවින් අවම වශයෙන් SQL සේවාදායකය සඳහා අපි තවමත් නිවැරදි කර නැත. වරහන් යුගලවලට විශේෂ අරුතක් ඇති හෙයින්, අපට ඒවායින් ද ගැලවිය යුතුය. අපි වරහන් නිසි ලෙස ගැලවීමට සමත් වුවහොත්, අවම වශයෙන් අපට වරහන් තුළ ඇති යටි ඉර -සහ කැරට් ගැන කරදර විය යුතු නැත ^. වරහන් වල ඇති විශේෂ අරුත අප මූලික වශයෙන් අක්‍රීය කර ඇති බැවින් අපට වරහන් තුළ ඇති ඕනෑම අක්ෂර %සහ _අක්ෂර ගැලවී යා හැකිය .

ගැලපෙන වරහන් යුගල සොයා ගැනීම එතරම් අපහසු නොවිය යුතුය. සිංගල්ටන්% සහ _ සිදුවීම් හැසිරවීමට වඩා එය ටිකක් අපහසුයි. . .)

පේළිගත ප්‍රකාශනය අවුල් සහගත වේ

SQL හි එම පේළිගත ප්‍රකාශනය දිගින් දිගට හා කැත වෙමින් පවතී. අපට එය ක්‍රියාත්මක කිරීමට බොහෝ විට හැකිය, නමුත් ස්වර්ගය පිටුපසින් පැමිණෙන දුප්පත් ආත්මයට උදව් කර එය තේරුම් ගත යුතුය. පේළිගත ප්‍රකාශන සඳහා මම බොහෝ රසිකයන් වන බැවින්, මම මෙහි එකක් භාවිතා නොකිරීමට කැමැත්තෙමි, ප්‍රධාන වශයෙන් මට අවුලට හේතුව පැහැදිලි කරමින් අදහස් දැක්වීමක් කිරීමට අවශ්‍ය නැති නිසා සහ ඒ සඳහා සමාව ඉල්ලමි.

ශ්‍රිතයක් කොහේද?

හරි, ඉතින්, අපි එය SQL හි පේළිගත ප්‍රකාශනයක් ලෙස හසුරුවන්නේ නැත්නම්, අපට ඇති ආසන්නතම විකල්පය පරිශීලක අර්ථ දක්වන ලද ශ්‍රිතයකි. ඒ වගේම කිසිම දෙයක් වේගවත් නොවන බව අපි දනිමු (අපට ඔරකල් සමඟ කළ හැකි පරිදි දර්ශකයක් නිර්වචනය කළ නොහැකි නම්.) අපට ශ්‍රිතයක් නිර්මාණය කිරීමට සිදුවුවහොත්, SQL ලෙස හඳුන්වන කේතයෙන් අපට එය කළ හැකිය. ප්රකාශය.

එම ශ්‍රිතයට DBMS සහ අනුවාදය මත රඳා පවතින හැසිරීම් වල යම් වෙනස්කම් තිබිය හැකිය. (ඕනෑම දත්ත සමුදා එන්ජිමක් එකිනෙකට වෙනස් ලෙස භාවිතා කිරීමට හැකිවීම ගැන ඔබ උනන්දුවක් දක්වන ජාවා සංවර්ධකයින්ට හ shout නඟන්න.)

වසම් දැනුම

තීරුව සඳහා වසම පිළිබඳ අපට විශේෂ knowledge දැනුමක් තිබිය හැකිය, (එනම්, තීරුව සඳහා බලාත්මක කළ හැකි අගයන් සමූහය. තීරුවේ ගබඩා කර ඇති අගයන් කිසි විටෙකත් ප්‍රතිශත ලකුණක්, අවධාරනය කිරීමක් හෝ වරහනක් අඩංගු නොවන බව අපි දනිමු . යුගල. එම අවස්ථාවේ දී, එම සිද්ධීන් ආවරණය වන බවට ඉක්මන් අදහස් දැක්වීමක් අපි ඇතුළත් කරමු.

තීරුවේ ගබඩා කර ඇති අගයන්% හෝ _ අක්ෂර සඳහා ඉඩ දිය හැකිය, නමුත් අවහිරතාවයකට එම අගයන් ගැලවීමට අවශ්‍ය විය හැකිය, සමහර විට අර්ථ දක්වන ලද අක්ෂරයක් භාවිතා කරමින්, අගයන් සංසන්දනය “ආරක්ෂිත” වැනි ය. නැවතත්, අවසර ලත් වටිනාකම් සමූහය පිළිබඳ ඉක්මන් අදහස් දැක්වීමක් සහ විශේෂයෙන් ගැලවීමේ චරිතයක් ලෙස කුමන චරිතය භාවිතා කරනවාද යන්න සහ ජොයෙල් ස්පොල්ස්කිගේ ප්‍රවේශය සමඟ යන්න.

එහෙත්, විශේෂිත දැනුම හා සහතිකයක් නොමැති නම්, අවම වශයෙන් එම අපැහැදිලි මුල්ලක සිදුවීම් හැසිරවීම ගැන සලකා බැලීම වැදගත් වන අතර, හැසිරීම සාධාරණද යන්න සහ “පිරිවිතරයන්ට අනුව” යන්න සලකා බැලීම වැදගත් වේ.


වෙනත් ගැටළු නැවත සකස් කර ඇත

පොදුවේ සලකා බැලිය යුතු වෙනත් කරුණු සමහරක් අනෙක් අය දැනටමත් ප්‍රමාණවත් ලෙස පෙන්වා දී ඇතැයි මම විශ්වාස කරමි.

  • SQL එන්නත් කිරීම (පරිශීලක විසින් සපයන ලද තොරතුරු ලෙස පෙනෙන දේ ගැනීම සහ ඒවා බන්ධන විචල්‍යයන් හරහා සැපයීමට වඩා SQL පා text යේ ඇතුළත් කිරීම. බන්ධන විචල්‍යයන් භාවිතා කිරීම අවශ්‍ය නොවේ, එය SQL එන්නත් කිරීම වළක්වාලීමට එක් පහසු ප්‍රවේශයක් පමණි. එය සමඟ ගනුදෙනු කළ හැකි ක්‍රම:

  • දර්ශක සෙවීමට වඩා දර්ශක පරිලෝකනය භාවිතා කරන ප්‍රශස්තිකරණ සැලැස්ම, ආදේශක කාඩ්පත් වලින් ගැලවීම සඳහා ප්‍රකාශනයක් හෝ ශ්‍රිතයක් අවශ්‍ය විය හැකිය (ප්‍රකාශනය හෝ ක්‍රියාකාරිත්වය පිළිබඳ දර්ශකය)

  • බන්ධන විචල්‍යයන් වෙනුවට වචනාර්ථමය අගයන් භාවිතා කිරීම පරිමාණයට බලපෑම් කරයි


නිගමනය

මම ජොයෙල් ස්පොල්ස්කිගේ ප්‍රවේශයට කැමතියි. එය දක්ෂයි. එය ක්රියා කරයි.

නමුත් මම එය දුටු විගසම එය සමඟ ඇතිවිය හැකි ගැටළුවක් දුටුවෙමි. එය ලිස්සා යාමට ඉඩ දීම මගේ ස්වභාවය නොවේ. මම අන් අයගේ උත්සාහය විවේචනය කිරීමට අදහස් නොකරමි. බොහෝ සංවර්ධකයින් ඔවුන්ගේ කාර්යයන් පෞද්ගලිකව ගන්නා බව මම දනිමි, මන්ද ඔවුන් ඒ සඳහා විශාල මුදලක් ආයෝජනය කරන අතර ඔවුන් ඒ ගැන එතරම් සැලකිල්ලක් දක්වයි. එබැවින් කරුණාකර තේරුම් ගන්න, මෙය පුද්ගලික ප්‍රහාරයක් නොවේ. මා මෙහිදී හඳුනාගෙන ඇත්තේ පරීක්‍ෂණයට වඩා නිෂ්පාදනයේ වර්ධනය වන ගැටලුවයි.

ඔව්, මම මුල් ප්‍රශ්නයට වඩා බොහෝ දුර ගොස් ඇත. නමුත් ප්‍රශ්නයක් සඳහා “තෝරාගත්” පිළිතුර සමඟ වැදගත් කාරණයක් ලෙස මා සලකන දේ සම්බන්ධයෙන් මෙම සටහන තැබිය යුත්තේ කොතැනින්ද?


ඔබ පරාමිතිගත විමසුම් භාවිතා කරන්නේ හෝ කැමති දැයි කරුණාකර අපට දන්වන්න පුළුවන්ද? මෙම විශේෂිත අවස්ථාවෙහිදී, 'පරාමිතිගත විමසුම් භාවිතා කරන්න' යන රීතිය ඉක්මවා ගොස් මුල් භාෂාව සමඟ සනීපාරක්ෂාව කිරීම නිවැරදි ද? ගොඩක් ස්තූතියි
ලුයිස් සිකොට්

2
U ලුයිස්: ඔව්, මම කැමතියි SQL ප්‍රකාශ වල බන්ධන විචල්‍යයන් භාවිතා කිරීමට, සහ ඒවා භාවිතා කරන විට පමණක් බන්ධන විචල්‍යයන් වළක්වනු ඇත. මුල් ගැටළුව සඳහා මගේ ප්‍රමිතිගත රටාව වනුයේ IN ලැයිස්තුවේ අවශ්‍ය ස්ථාන දරන්නන් සංඛ්‍යාව සමඟ SQL ප්‍රකාශය ගතිකව නිර්මාණය කිරීමයි, ඉන්පසු සෑම අගයක්ම එක් ස්ථානයකට බැඳ තබන්න. මාක් බ්‍රැකට්ගේ පිළිතුර බලන්න, එය මා (සහ තවත් 231) ඉහළට ඔසවා තැබූ පිළිතුරයි.
spencer7593

133

ඔබට පරාමිතිය නූලක් ලෙස සම්මත කළ හැකිය

ඉතින් ඔබට නූලක් තිබේ

DECLARE @tags

SET @tags = ruby|rails|scruffy|rubyonrails

select * from Tags 
where Name in (SELECT item from fnSplit(@tags, ‘|’))
order by Count desc

එවිට ඔබ කළ යුත්තේ 1 පරාමිතිය ලෙස නූල පසු කිරීම පමණි.

මෙන්න මම භාවිතා කරන භේදය ශ්‍රිතය.

CREATE FUNCTION [dbo].[fnSplit](
    @sInputList VARCHAR(8000) -- List of delimited items
  , @sDelimiter VARCHAR(8000) = ',' -- delimiter that separates items
) RETURNS @List TABLE (item VARCHAR(8000))

BEGIN
DECLARE @sItem VARCHAR(8000)
WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
 BEGIN
 SELECT
  @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,@sInputList,0)-1))),
  @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))

 IF LEN(@sItem) > 0
  INSERT INTO @List SELECT @sItem
 END

IF LEN(@sInputList) > 0
 INSERT INTO @List SELECT @sInputList -- Put the last item in
RETURN
END

2
මෙම ප්‍රවේශය සමඟ ඔබට මේස ක්‍රියාකාරිත්වයට සම්බන්ධ විය හැකිය.
මයිකල් හරන්

මම ඔරකල්හි මේ හා සමාන විසඳුමක් භාවිතා කරමි. වෙනත් විසඳුම් මෙන් එය නැවත විග්‍රහ කිරීමට අවශ්‍ය නැත.
ලී රිෆල්

9
මෙය පිරිසිදු දත්ත සමුදා ප්‍රවේශයකි, අනෙක දත්ත සමුදායෙන් පිටත කේතයේ වැඩ කිරීම අවශ්‍ය වේ.
ඩේවිඩ් බසරාබ්

මෙය වගු පරිලෝකනයකට හෝ දර්ශක ආදියෙන් ප්‍රයෝජන ගත හැකිද?
පිරිසිදු.ක්‍රොම්

SQL වගු ශ්‍රිතයට (අවම වශයෙන් 2005 සිට) ක්‍රොස් ඇප්ලි භාවිතා කිරීම වඩා හොඳ වනු ඇත, එය අත්‍යවශ්‍යයෙන්ම ආපසු ලබා දුන් වගුවට සම්බන්ධ වේ
ඇඩොල්ෆ් සුදුළූණු

66

අද දින පොඩ්කාස්ට් එකේදී ජෙෆ් / ජොයෙල් මේ ගැන කතා කිරීම මට ඇසුණි ( කථාංගය 34 , 2008-12-16 (MP3, 31 MB), 1 පැය 03 මිනිත්තු 38 තත්පර - 1 පැය 06 විනාඩි 45 තත්පර), මම සිතුවේ ස්ටැක් පිටාර ගැලීම සිහිපත් වූ බවයි. SQL වෙත LINQ භාවිතා කරමින් සිටියද සමහර විට එය ඉවත් කර ඇත. මෙන්න LINQ සිට SQL දක්වා එකම දේ.

var inValues = new [] { "ruby","rails","scruffy","rubyonrails" };

var results = from tag in Tags
              where inValues.Contains(tag.Name)
              select tag;

ඒක තමයි. ඔව්, ලින්ක් දැනටමත් පසුපසට පෙනෙන සේ පෙනේ, නමුත් Containsවගන්තිය මට පිටුපසට වැඩිපුර පෙනේ. වැඩ කරන ව්‍යාපෘතියක් සඳහා මට සමාන විමසුමක් කිරීමට සිදු වූ විට, මම ස්වභාවිකවම දේශීය අරා සහ SQL සේවාදායක වගුව අතර සම්බන්ධයක් ඇති කර ගැනීමෙන් මෙය වැරදි ලෙස කිරීමට උත්සාහ කළෙමි. පරිවර්තනය කෙසේ හෝ. එය එසේ නොවීය, නමුත් එය විස්තරාත්මක දෝෂ පණිවිඩයක් සපයන අතර අන්තර්ගතය භාවිතා කිරීමට මා යොමු කළේය.

කෙසේ වෙතත්, ඔබ මෙය බෙහෙවින් නිර්දේශිත LINQPad තුළ ධාවනය කර මෙම විමසුම ක්‍රියාත්මක කරන්නේ නම්, ඔබට SQL LINQ සැපයුම්කරු විසින් ජනනය කරන ලද සත්‍ය SQL බැලීමට හැකිය. එය එක් එක් අගයන් INවගන්තියකට පරාමිතිගත කිරීම පෙන්වයි .


50

ඔබ .NET වෙතින් අමතන්නේ නම්, ඔබට ඩැපර් ඩොට් නෙට් භාවිතා කළ හැකිය :

string[] names = new string[] {"ruby","rails","scruffy","rubyonrails"};
var tags = dataContext.Query<Tags>(@"
select * from Tags 
where Name in @names
order by Count desc", new {names});

මෙන්න ඩැපර් චින්තනය කරයි, එබැවින් ඔබට එසේ කිරීමට අවශ්‍ය නැත. LINQ සිට SQL දක්වා සමාන දෙයක් කළ හැකිය , ඇත්ත වශයෙන්ම:

string[] names = new string[] {"ruby","rails","scruffy","rubyonrails"};
var tags = from tag in dataContext.Tags
           where names.Contains(tag.Name)
           orderby tag.Count descending
           select tag;

11
අසන ලද සත්‍ය ප්‍රශ්නය සඳහා ( ඩැපර්
සෑම් කුංකුම


නම් දිගු නම් මෙය අවසන් වේ
cs0815

31

දී SQL Server 2016+භාවිතා කිරීමට ඔබට හැකිය STRING_SPLITක්රියාව:

DECLARE @names NVARCHAR(MAX) = 'ruby,rails,scruffy,rubyonrails';

SELECT * 
FROM Tags
WHERE Name IN (SELECT [value] FROM STRING_SPLIT(@names, ','))
ORDER BY [Count] DESC;

හෝ:

DECLARE @names NVARCHAR(MAX) = 'ruby,rails,scruffy,rubyonrails';

SELECT t.*
FROM Tags t
JOIN STRING_SPLIT(@names,',')
  ON t.Name = [value]
ORDER BY [Count] DESC;

LiveDemo

මෙම පිළිගත් පිළිතුර පාඨමාලාව වැඩ කැමැත්ත සහ එය ඉදිරියට යා හැකි එකකි, නමුත් එය ප්රති-රටාව වේ.

E. අගයන් ලැයිස්තුවෙන් පේළි සොයන්න

යෙදුම් ස්ථරයේ හෝ ගණුදෙනු- SQL තුළ ගතික SQL නූලක් සෑදීම හෝ LIKE ක්‍රියාකරු භාවිතා කිරීම වැනි පොදු ප්‍රති-රටාවන් සඳහා මෙය ප්‍රතිස්ථාපනය වේ:

SELECT ProductId, Name, Tags
FROM Product
WHERE ',1,2,3,' LIKE '%,' + CAST(ProductId AS VARCHAR(20)) + ',%';

අතිරේක :

STRING_SPLITවගු ශ්‍රිත පේළි ඇස්තමේන්තුව වැඩි දියුණු කිරීම සඳහා, බෙදී ගිය අගයන් තාවකාලික වගුව / වගු විචල්‍යය ලෙස ක්‍රියාවට නැංවීම හොඳ අදහසකි:

DECLARE @names NVARCHAR(MAX) = 'ruby,rails,scruffy,rubyonrails,sql';

CREATE TABLE #t(val NVARCHAR(120));
INSERT INTO #t(val) SELECT s.[value] FROM STRING_SPLIT(@names, ',') s;

SELECT *
FROM Tags tg
JOIN #t t
  ON t.val = tg.TagName
ORDER BY [Count] DESC;

SEDE - සජීවී නිරූපණය

ආශ්‍රිත: ගබඩා කළ ක්‍රියා පටිපාටියකට සාරධර්ම ලැයිස්තුවක් සම්මත කරන්නේ කෙසේද?


මුල් ප්‍රශ්නයට අවශ්‍යතාවයක් SQL Server 2008ඇත. මෙම ප්‍රශ්නය බොහෝ විට අනුපිටපතක් ලෙස භාවිතා කර ඇති නිසා, මම මෙම පිළිතුර යොමු කිරීමක් ලෙස එකතු කර ඇත්තෙමි.


1
මම මෙය පරිපූර්ණ ලෙස අත්හදා බලා නැත, නමුත් මෙය පිරිසිදු 2016+ විසඳුම යැයි මට හැඟේ. මම තවමත් කැමතියි int කාණ්ඩයක් පසුකර යාමට, නමුත් එතෙක් ...
ඩැනියෙල්

29

මෙය සමහර විට එය අඩක් නපුරු ක්‍රමයක් විය හැකිය, මම එය වරක් භාවිතා කළෙමි, තරමක් was ලදායී විය.

ඔබගේ අරමුණු මත පදනම්ව එය ප්‍රයෝජනවත් විය හැකිය.

  1. එක් තීරුවක් සමඟ තාවකාලික වගුවක් සාදන්න .
  2. INSERT එක් එක් බැලීමේ අගය එම තීරුවට.
  3. භාවිතා කිරීම වෙනුවට IN, ඔබට ඔබේ සම්මත JOINනීති භාවිතා කළ හැකිය . (නම්‍යශීලීභාවය ++)

මෙය ඔබට කළ හැකි දේවල තරමක් අමතර නම්‍යතාවයක් ඇත, නමුත් හොඳ සුචිගත කිරීමක් සහිතව විමසීමට ඔබට විශාල වගුවක් ඇති අවස්ථාවන්ට එය වඩාත් සුදුසු වන අතර පරාමිතිගත ලැයිස්තුව එක් වරකට වඩා භාවිතා කිරීමට ඔබට අවශ්‍යය. එය දෙවරක් ක්‍රියාත්මක කිරීම හා සියලු සනීපාරක්ෂාව අතින් සිදු කිරීම ඉතිරි කරයි.

මම හරියටම ආකාරය ලක්කිරීම වටා ලැබුණේ නැහැ වේගයෙන් එය, නමුත් ඒ ගැන මගේ තත්වය තුල අවශ්ය විය.


මෙය කිසිසේත් නරක නැත! ඊටත් වඩා, එය IMHO ඉතා පිරිසිදු ක්‍රමයකි. ඔබ ක්‍රියාත්මක කිරීමේ සැලැස්ම දෙස බැලුවහොත්, එය IN වගන්තියට සමාන බව ඔබට පෙනේ. තාවකාලික වගුවක් වෙනුවට, ඔබට දර්ශක සහිත ස්ථාවර වගුවක් සෑදිය හැකිය, එහිදී ඔබ SESSIONID සමඟ පරාමිතීන් ගබඩා කරයි.
SQL පොලිස්

24

ඔබට සම්බන්ධ විය හැකි වගු විචල්‍යයක් නිර්මාණය කරන ශ්‍රිතයක් අප සතුව ඇත:

ALTER FUNCTION [dbo].[Fn_sqllist_to_table](@list  AS VARCHAR(8000),
                                           @delim AS VARCHAR(10))
RETURNS @listTable TABLE(
  Position INT,
  Value    VARCHAR(8000))
AS
  BEGIN
      DECLARE @myPos INT

      SET @myPos = 1

      WHILE Charindex(@delim, @list) > 0
        BEGIN
            INSERT INTO @listTable
                        (Position,Value)
            VALUES     (@myPos,LEFT(@list, Charindex(@delim, @list) - 1))

            SET @myPos = @myPos + 1

            IF Charindex(@delim, @list) = Len(@list)
              INSERT INTO @listTable
                          (Position,Value)
              VALUES     (@myPos,'')

            SET @list = RIGHT(@list, Len(@list) - Charindex(@delim, @list))
        END

      IF Len(@list) > 0
        INSERT INTO @listTable
                    (Position,Value)
        VALUES     (@myPos,@list)

      RETURN
  END 

නිසා:

@Name varchar(8000) = null // parameter for search values    

select * from Tags 
where Name in (SELECT value From fn_sqllist_to_table(@Name,',')))
order by Count desc

20

මෙය දළ ය, නමුත් ඔබට අවම වශයෙන් එකක් වත් ඇති බවට සහතික නම්, ඔබට කළ හැක්කේ:

SELECT ...
       ...
 WHERE tag IN( @tag1, ISNULL( @tag2, @tag1 ), ISNULL( @tag3, @tag1 ), etc. )

IN ('tag1', 'tag2', 'tag1', 'tag1', 'tag1') තිබීම SQL සේවාදායකය විසින් පහසුවෙන් ප්‍රශස්තිකරණය කරනු ඇත. ඊට අමතරව, ඔබට index ජු දර්ශක සෙවීම් ලැබේ


1
ප්‍රශස්තකරණයට කාර්යක්ෂම විමසුම් නිර්මාණය කිරීම සඳහා භාවිතා කරන පරාමිති ගණන අවශ්‍ය බැවින් ශුන්‍ය චෙක්පත් සමඟ විකල්ප පරාමිතීන් කාර්ය සාධනය නරක් කරයි. පරාමිති 5 ක් සඳහා විමසුමකට පරාමිති 500 කට එකකට වඩා වෙනස් විමසුම් සැලැස්මක් අවශ්‍ය විය හැකිය.
එරික් හාර්ට්

18

මගේ මතය අනුව, මෙම ගැටළුව විසඳීමට ඇති හොඳම ප්‍රභවය නම්, මෙම වෙබ් අඩවියේ පළ කර ඇති දේ:

අක්‍රමිකතා. දිනකාර් නේති

CREATE FUNCTION dbo.fnParseArray (@Array VARCHAR(1000),@separator CHAR(1))
RETURNS @T Table (col1 varchar(50))
AS 
BEGIN
 --DECLARE @T Table (col1 varchar(50))  
 -- @Array is the array we wish to parse
 -- @Separator is the separator charactor such as a comma
 DECLARE @separator_position INT -- This is used to locate each separator character
 DECLARE @array_value VARCHAR(1000) -- this holds each array value as it is returned
 -- For my loop to work I need an extra separator at the end. I always look to the
 -- left of the separator character for each array value

 SET @array = @array + @separator

 -- Loop through the string searching for separtor characters
 WHILE PATINDEX('%' + @separator + '%', @array) <> 0 
 BEGIN
    -- patindex matches the a pattern against a string
    SELECT @separator_position = PATINDEX('%' + @separator + '%',@array)
    SELECT @array_value = LEFT(@array, @separator_position - 1)
    -- This is where you process the values passed.
    INSERT into @T VALUES (@array_value)    
    -- Replace this select statement with your processing
    -- @array_value holds the value of this element of the array
    -- This replaces what we just processed with and empty string
    SELECT @array = STUFF(@array, 1, @separator_position, '')
 END
 RETURN 
END

භාවිත:

SELECT * FROM dbo.fnParseArray('a,b,c,d,e,f', ',')

ණය: දිනකර් නේති


ආරම්භක CSV වගුවකට විග්‍රහ කිරීම හැරෙන්නට විශිෂ්ට පිළිතුර, පිරිසිදු හා මොඩියුලර්, සුපිරි වේගවත් ක්‍රියාත්මක කිරීම (එක් වරක්, මූලද්‍රව්‍ය කුඩා සංඛ්‍යාවක්). Patindex () වෙනුවට සරල / වේගවත් charindex () භාවිතා කළ හැකි වුවද? Charindex () මඟින් 'start_location' යන තර්කයට ඉඩ ලබා දෙන අතර එමඟින් එක් එක් iter එකෙහි ආදාන නූල් කැපීම වළක්වා ගත හැකිද? මුල් ප්‍රශ්නයට පිළිතුරු සැපයීම සඳහා ක්‍රියාකාරී ප්‍රති .ල සමඟ සම්බන්ධ විය හැකිය.
crokusek

18

මම මේස වර්ගයේ පරාමිතියක් පසුකර යන්නෙමි (එය SQL Server 2008 බැවින් ), සහ where existsඅභ්‍යන්තර සම්බන්ධතාවයක් කරන්න. ඔබට XML භාවිතා කිරීම, භාවිතා කිරීම sp_xml_preparedocumentසහ පසුව එම තාවකාලික වගුව සුචිගත කිරීම ද කළ හැකිය.


Ph.E හි පිළිතුරට තාවකාලික වගුවක් තැනීම සඳහා උදාහරණයක් ඇත (csv වෙතින්).
crokusek

12

IMHO සඳහා සුදුසුම ක්‍රමය නම් ලැයිස්තුව අක්ෂර මාලාවක ගබඩා කිරීමයි (ඩීබීඑම්එස් සහාය දක්වන ප්‍රමාණය අනුව දිගට සීමා වේ); එකම උපක්‍රමය නම් (සැකසීම සරල කිරීම සඳහා) ආරම්භයේ දී සහ අවසානයේ දී මට බෙදුම්කරුවෙකු (මගේ උදාහරණයේ කොමාව) ඇත. අදහස වන්නේ "මැස්ස මත සාමාන්‍යකරණය කිරීම", ලැයිස්තුව එක් තීරුවක වගුවකට හරවා එක් අගයකට එක් පේළියක් ඇතුළත් කිරීමයි. මෙය ඔබට හැරවීමට ඉඩ දෙයි

තුළ (ct1, ct2, ct3 ... ctn)

තුළ (තෝරන්න ...)

හෝ (මම බොහෝ විට කැමති විසඳුම) ලැයිස්තුවේ අනුපිටපත් අගයන් සමඟ ඇති ගැටළු මඟහරවා ගැනීම සඳහා ඔබ “වෙනස්” එකතු කළහොත් නිතිපතා සම්බන්ධ වීම.

අවාසනාවකට මෙන්, නූලක් කැපීමේ ශිල්පීය ක්‍රම තරමක් නිෂ්පාදන විශේෂිත වේ. මෙන්න SQL සේවාදායක අනුවාදය:

 with qry(n, names) as
       (select len(list.names) - len(replace(list.names, ',', '')) - 1 as n,
               substring(list.names, 2, len(list.names)) as names
        from (select ',Doc,Grumpy,Happy,Sneezy,Bashful,Sleepy,Dopey,' names) as list
        union all
        select (n - 1) as n,
               substring(names, 1 + charindex(',', names), len(names)) as names
        from qry
        where n > 1)
 select n, substring(names, 1, charindex(',', names) - 1) dwarf
 from qry;

ඔරකල් අනුවාදය:

 select n, substr(name, 1, instr(name, ',') - 1) dwarf
 from (select n,
             substr(val, 1 + instr(val, ',', 1, n)) name
      from (select rownum as n,
                   list.val
            from  (select ',Doc,Grumpy,Happy,Sneezy,Bashful,Sleepy,Dopey,' val
                   from dual) list
            connect by level < length(list.val) -
                               length(replace(list.val, ',', ''))));

සහ MySQL අනුවාදය:

select pivot.n,
      substring_index(substring_index(list.val, ',', 1 + pivot.n), ',', -1) from (select 1 as n
     union all
     select 2 as n
     union all
     select 3 as n
     union all
     select 4 as n
     union all
     select 5 as n
     union all
     select 6 as n
     union all
     select 7 as n
     union all
     select 8 as n
     union all
     select 9 as n
     union all
     select 10 as n) pivot,    (select ',Doc,Grumpy,Happy,Sneezy,Bashful,Sleepy,Dopey,' val) as list where pivot.n <  length(list.val) -
                   length(replace(list.val, ',', ''));

(ඇත්ත වශයෙන්ම, "හැරීම" අපට ලැයිස්තුවේ සොයාගත හැකි උපරිම අයිතම ගණන තරම් පේළි ගණනක් ආපසු ලබා දිය යුතුය)


11

ඔබට SQL සේවාදායකය 2008 හෝ ඊට පසු තිබේ නම් මම වගු අගය සහිත පරාමිතියක් භාවිතා කරමි .

ඔබ SQL Server 2005 හි සිරවී සිටීමට තරම් අවාසනාවන්ත නම් ඔබට මේ වගේ CLR ශ්‍රිතයක් එක් කළ හැකිය ,

[SqlFunction(
    DataAccessKind.None,
    IsDeterministic = true,
    SystemDataAccess = SystemDataAccessKind.None,
    IsPrecise = true,
    FillRowMethodName = "SplitFillRow",
    TableDefinintion = "s NVARCHAR(MAX)"]
public static IEnumerable Split(SqlChars seperator, SqlString s)
{
    if (s.IsNull)
        return new string[0];

    return s.ToString().Split(seperator.Buffer);
}

public static void SplitFillRow(object row, out SqlString s)
{
    s = new SqlString(row.ToString());
}

ඔබට මේ ආකාරයෙන් භාවිතා කළ හැකි,

declare @desiredTags nvarchar(MAX);
set @desiredTags = 'ruby,rails,scruffy,rubyonrails';

select * from Tags
where Name in [dbo].[Split] (',', @desiredTags)
order by Count desc

10

ස්ථිතික විමසුමක් යනු යා යුතු මාර්ගය නොවන විට මෙය අවස්ථාවක් යැයි මම සිතමි. ඔබේ වගන්තිය සඳහා ගතිකව ලැයිස්තුව ගොඩනඟන්න, ඔබේ තනි උපුටා දැක්වීම් වලින් ගැලවී SQL ගතිකව ගොඩනඟන්න. මෙම අවස්ථාවෙහිදී, කුඩා ලැයිස්තුව නිසා ඔබට ඕනෑම ක්‍රමයක් සමඟ බොහෝ වෙනසක් නොපෙනේ, නමුත් වඩාත්ම කාර්යක්ෂම ක්‍රමය වන්නේ ඔබේ පෝස්ට් එකේ ලියා ඇති ආකාරයටම SQL යැවීමයි. ලස්සනම කේතය බවට පත්කිරීමට වඩා එය වඩාත් කාර්යක්ෂම ආකාරයකින් ලිවීම හොඳ පුරුද්දක් යැයි මම සිතමි, නැතහොත් SQL ගතිකව ගොඩනැගීම නරක පුරුද්දක් ලෙස සලකමි.

පරාමිතීන් විශාල වන බොහෝ අවස්ථාවන්හිදී බෙදීම් ශ්‍රිතයන් විමසීමට වඩා වැඩි කාලයක් ගත වන බව මම දැක ඇත්තෙමි. SQL 2008 හි වගු වටිනාකමින් යුත් පරාමිතීන් සහිත ගබඩා කළ ක්‍රියා පටිපාටියක් මම සලකා බලන අනෙක් විකල්පයයි, මෙය ඔබගේ නඩුවේ මන්දගාමී වනු ඇත. TVP බොහෝ විට වේගවත් වනු ඇත්තේ ඔබ TVP හි ප්‍රාථමික යතුර සොයන්නේ නම් පමණි, මන්ද SQL කෙසේ හෝ ලැයිස්තුව සඳහා තාවකාලික වගුවක් සාදනු ඇත (ලැයිස්තුව විශාල නම්). ඔබ එය පරීක්ෂා නොකරන්නේ නම් ඔබ නිසැකවම දැන නොගනු ඇත.

පෙරනිමි අගයන් සහිත පරාමිති 500 ක් සහ WHERE Column1 IN (@ Param1, @ Param2, @ Param3, ..., @ Param500) සහිත ගබඩා කර ඇති ක්‍රියා පටිපාටි ද මම දැක ඇත්තෙමි. මෙය SQL තාවකාලික වගුවක් තැනීමට, වර්ග කිරීමක් / වෙනස් කිරීමක් කිරීමට, පසුව දර්ශක සෙවීම වෙනුවට මේස පරිලෝකනය කිරීමට හේතු විය. එම විමසුම පරාමිතිකරණය කිරීමෙන් ඔබ කරන්නේ එයයි, කුඩා පරිමාණයෙන් එය සැලකිය යුතු වෙනසක් සිදු නොකරනු ඇත. ඔබගේ IN ලැයිස්තු වල NULL තිබීමට එරෙහිව මම තරයේ නිර්දේශ කරමි, එය NOT IN ලෙස වෙනස් වුවහොත් එය අපේක්ෂිත පරිදි ක්‍රියා නොකරනු ඇත. ඔබට පරාමිති ලැයිස්තුව ගතිකව ගොඩනගා ගත හැකිය, නමුත් ඔබට ලැබිය හැකි එකම පැහැදිලි දෙය නම් වස්තූන් ඔබ වෙනුවෙන් තනි මිල ගණන් වලින් ගැලවී යාමයි. පරාමිතීන් සොයා ගැනීම සඳහා වස්තුව විමසුම විග්‍රහ කළ යුතු බැවින් යෙදුම් ප්‍රවේශය මත එම ප්‍රවේශය ද තරමක් මන්දගාමී වේ.

ගබඩා කර ඇති ක්‍රියා පටිපාටි හෝ පරාමිතිගත විමසුම් සඳහා ක්‍රියාත්මක කිරීමේ සැලසුම් නැවත භාවිතා කිරීම මඟින් ඔබට කාර්ය සාධනයක් ලබා ගත හැකි නමුත්, එය ක්‍රියාත්මක කරන පළමු විමසුම මගින් තීරණය කරනු ලබන එක් ක්‍රියාත්මක කිරීමේ සැලැස්මකට ඔබව අගුළු දමනු ඇත. බොහෝ අවස්ථාවන්හි පසුකාලීන විමසුම් සඳහා එය පරමාදර්ශයට වඩා අඩු විය හැකිය. ඔබේ නඩුවේදී, ක්‍රියාත්මක කිරීමේ සැලසුම් නැවත භාවිතා කිරීම බොහෝ විට වාසියක් වනු ඇත, නමුත් උදාහරණය ඇත්තෙන්ම සරල විමසුමකි.

කඳු බෑවුම් සටහන්:

ඔබගේ නඩුව සඳහා ඔබ කරන ඕනෑම දෙයක් නම්, එය ලැයිස්තුවේ ඇති නිශ්චිත අයිතම සංඛ්‍යාවක් සමඟ පරාමිතිකරණය (භාවිතා නොකරන්නේ නම්), පරාමිතීන් සමඟ හෝ රහිතව විමසුම ගතිකව ගොඩනඟා ගැනීම හෝ වගු වටිනාකමින් යුත් පරාමිතීන් සමඟ ගබඩා කළ ක්‍රියා පටිපාටි භාවිතා කිරීම විශාල වෙනසක් නොකරනු ඇත. . කෙසේ වෙතත්, මගේ පොදු නිර්දේශ පහත පරිදි වේ:

ඔබේ නඩුව / පරාමිති කිහිපයක් සහිත සරල විමසුම්:

ගතික SQL, සමහර විට පරාමිතීන් සමඟ පරීක්ෂණ වඩා හොඳ කාර්ය සාධනයක් පෙන්වයි.

නැවත භාවිතා කළ හැකි ක්‍රියාත්මක කිරීමේ සැලසුම් සහිත විමසුම්, පරාමිතීන් වෙනස් කිරීමෙන් හෝ විමසුම සංකීර්ණ නම් කිහිප වතාවක්ම හැඳින්වේ:

ගතික පරාමිතීන් සහිත SQL.

විශාල ලැයිස්තු සහිත විමසුම්:

වගු වටිනාකමින් යුත් පරාමිතීන් සමඟ ගබඩා කළ පටිපාටිය. ලැයිස්තුව විශාල ප්‍රමාණයකින් වෙනස් විය හැකි නම්, ගබඩා කළ ක්‍රියාපටිපාටිය මත නිර්දේශය සමඟ භාවිතා කරන්න, නැතහොත් එක් එක් විමසුම සඳහා නව ක්‍රියාත්මක කිරීමේ සැලැස්මක් ජනනය කිරීම සඳහා පරාමිතීන් නොමැතිව ගතික SQL භාවිතා කරන්න.


මෙහි “ගබඩා කළ ක්‍රියා පටිපාටිය” යන්නෙන් ඔබ අදහස් කරන්නේ කුමක්ද? ඔබට උදාහරණයක් පළ කළ හැකිද?
struhtanov

9

අපට මෙහි XML භාවිතා කළ හැකිය:

    declare @x xml
    set @x='<items>
    <item myvalue="29790" />
    <item myvalue="31250" />
    </items>
    ';
    With CTE AS (
         SELECT 
            x.item.value('@myvalue[1]', 'decimal') AS myvalue
        FROM @x.nodes('//items/item') AS x(item) )

    select * from YourTable where tableColumnName in (select myvalue from cte)

1
CTEහා @x/ මෙම subselect බවට inlined, ඉතා ප්රවේශමෙන් සිදු නම්, පහත රූපයේ පරිදි නැති කර ගත හැකිය මෙම ලිපිය .
robert4

9

පෙරනිමියෙන් මම මේ සඳහා ප්‍රවේශ වන්නේ වගු වටිනාකමින් යුත් ශ්‍රිතයක් (එය නූලකින් වගුවක් ආපසු ලබා දෙන) IN තත්වයට යැවීමෙනි.

මෙන්න යූඩීඑෆ් සඳහා කේතය (මම එය කොහේ හෝ තැනක සිට ගලා ආවෙමි, මට දැන් මූලාශ්‍රය සොයාගත නොහැක)

CREATE FUNCTION [dbo].[Split] (@sep char(1), @s varchar(8000))
RETURNS table
AS
RETURN (
    WITH Pieces(pn, start, stop) AS (
      SELECT 1, 1, CHARINDEX(@sep, @s)
      UNION ALL
      SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1)
      FROM Pieces
      WHERE stop > 0
    )
    SELECT 
      SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
    FROM Pieces
  )

ඔබ මෙය ලබා ගත් පසු ඔබේ කේතය මේ තරම් සරල වනු ඇත:

select * from Tags 
where Name in (select s from dbo.split(';','ruby;rails;scruffy;rubyonrails'))
order by Count desc

ඔබට හාස්‍යජනක ලෙස දිගු නූලක් නොමැති නම්, මෙය වගු දර්ශකය සමඟ හොඳින් ක්‍රියා කළ යුතුය.

අවශ්‍ය නම් ඔබට එය තාවකාලික වගුවකට ඇතුළත් කළ හැකිය, එය සුචිගත කරන්න, පසුව සම්බන්ධතාවයක් ධාවනය කරන්න ...


8

තවත් විසඳුමක් නම්, ගබඩා කළ ක්‍රියා පටිපාටියකට විචල්‍ය තර්ක සංඛ්‍යාවක් යැවීම වෙනුවට, ඔබට පසුව නම් ඇතුළත් තනි නූලක් පසුකර යන්න, නමුත් ඒවා '<>' සමඟ වට කර ඒවා අද්විතීය කරන්න. ඉන්පසු නම් සොයා ගැනීමට PATINDEX භාවිතා කරන්න:

SELECT * 
FROM Tags 
WHERE PATINDEX('%<' + Name + '>%','<jo>,<john>,<scruffy>,<rubyonrails>') > 0

8

පහත ගබඩා කළ ක්‍රියා පටිපාටිය භාවිතා කරන්න. එය අභිරුචි බෙදීම් ශ්‍රිතයක් භාවිතා කරයි, එය මෙහි සොයාගත හැකිය .

 create stored procedure GetSearchMachingTagNames 
    @PipeDelimitedTagNames varchar(max), 
    @delimiter char(1) 
    as  
    begin
         select * from Tags 
         where Name in (select data from [dbo].[Split](@PipeDelimitedTagNames,@delimiter) 
    end

8

කොමා (,) සමඟ වෙන් කර ඇති IN වගන්තිය තුළ අප සතුව ගබඩා කර ඇති නූල් තිබේ නම්, අපට අගයන් ලබා ගැනීම සඳහා charindex ශ්‍රිතය භාවිතා කළ හැකිය. ඔබ .NET භාවිතා කරන්නේ නම්, ඔබට SqlParameters සමඟ සිතියම් ගත කළ හැකිය.

ඩීඩීඑල් පිටපත:

CREATE TABLE Tags
    ([ID] int, [Name] varchar(20))
;

INSERT INTO Tags
    ([ID], [Name])
VALUES
    (1, 'ruby'),
    (2, 'rails'),
    (3, 'scruffy'),
    (4, 'rubyonrails')
;

T-SQL:

DECLARE @Param nvarchar(max)

SET @Param = 'ruby,rails,scruffy,rubyonrails'

SELECT * FROM Tags
WHERE CharIndex(Name,@Param)>0

ඔබට ඉහත ප්‍රකාශය ඔබේ .NET කේතයෙන් භාවිතා කර පරාමිතිය SqlParameter සමඟ සිතියම් ගත කළ හැකිය.

ෆිද්ලර් නිරූපණය

සංස්කරණය කරන්න: කරන්න පහත දැක්වෙන ස්ක්‍රිප්ට් භාවිතයෙන් තෝරාගත් නම් වගුව සාදන්න.

ඩීඩීඑල් පිටපත:

Create table SelectedTags
(Name nvarchar(20));

INSERT INTO SelectedTags values ('ruby'),('rails')

T-SQL:

DECLARE @list nvarchar(max)
SELECT @list=coalesce(@list+',','')+st.Name FROM SelectedTags st

SELECT * FROM Tags
WHERE CharIndex(Name,@Param)>0

හැකි අගයන් පිළිබඳ දෘඩ කේත ලැයිස්තුවක් නොමැති තැන මෙම වැඩ කිරීම පිළිබඳ උදාහරණයක් ඔබට පෙන්විය හැකිද?
ජෝන් සෝන්ඩර්ස්

O ජෝන් සොන්ඩර්ස්, මම කිසිදු දෘ c කේත ලැයිස්තුවක් භාවිතා නොකර පිටපත සංස්කරණය කර ඇත්තෙමි. තහවුරු කරන්න.
Gowdhaman008

3
මෙම විකල්පය සමඟ එක් සීමාවක්. නූල හමු වුවහොත් CharIndex 1 නැවත ලබා දෙයි. IN නියම නියමයන් සඳහා තරඟයක් ලබා දෙයි. "Stack" සඳහා CharIndex "StackOverflow" IN යන යෙදුම සඳහා 1 ක් ආපසු ලබා දෙනු ඇත. ඉහත සීමාව ඉක්මවා යන '<'% name% '>' සමඟ නම් ඇතුළත් කර ඇති ඉහත PatIndex භාවිතා කරමින් මෙම පිළිතුරට සුළු වෙනස් කිරීමක් ඇත. මෙම ගැටලුවට නිර්මාණාත්මක විසඳුමක් වුවද.
රිචඩ් විවියන්

7

මේ ආකාරයේ විචල්‍ය තර්ක සංඛ්‍යාවක් සඳහා මා දන්නා එකම ක්‍රමය වන්නේ SQL පැහැදිලිව උත්පාදනය කිරීම හෝ ඔබට අවශ්‍ය අයිතම සමඟ තාවකාලික වගුවක් පුරවා තාවකාලික වගුවට සම්බන්ධ වීම වැනි දෙයක් කිරීමයි.


7

දී ColdFusion අපි කරන්න:

<cfset myvalues = "ruby|rails|scruffy|rubyonrails">
    <cfquery name="q">
        select * from sometable where values in <cfqueryparam value="#myvalues#" list="true">
    </cfquery>

7

විමසුම් නූලක භාවිතා කිරීමට දේශීය වගුවක් ප්‍රතිනිර්මාණය කරන තාක්‍ෂණය මෙන්න. මේ ආකාරයට කිරීමෙන් සියලු විග්‍රහ කිරීමේ ගැටළු ඉවත් වේ.

නූල ඕනෑම භාෂාවකින් ගොඩනගා ගත හැකිය. මෙම උදාහරණයේ දී මම SQL භාවිතා කළේ එය විසඳීමට උත්සාහ කළ මුල් ගැටළුව වූ බැවිනි. පසුව ක්‍රියාත්මක කිරීම සඳහා නූලකින් පියාසර වගුවේ දත්ත යැවීමට මට පිරිසිදු ක්‍රමයක් අවශ්‍ය විය.

පරිශීලක අර්ථ දක්වන ලද වර්ගයක් භාවිතා කිරීම අත්‍යවශ්‍ය නොවේ. වර්ගය නිර්මාණය කිරීම එක් වරක් පමණක් නිර්මාණය කර ඇති අතර එය කල්තියා කළ හැකිය. එසේ නොමැතිනම් නූලෙහි ප්‍රකාශයට සම්පූර්ණ වගු වර්ගයක් එක් කරන්න.

සාමාන්‍ය රටාව දිගු කිරීම පහසු වන අතර වඩාත් සංකීර්ණ වගු පසු කිරීම සඳහා භාවිතා කළ හැකිය.

-- Create a user defined type for the list.
CREATE TYPE [dbo].[StringList] AS TABLE(
    [StringValue] [nvarchar](max) NOT NULL
)

-- Create a sample list using the list table type.
DECLARE @list [dbo].[StringList]; 
INSERT INTO @list VALUES ('one'), ('two'), ('three'), ('four')

-- Build a string in which we recreate the list so we can pass it to exec
-- This can be done in any language since we're just building a string.
DECLARE @str nvarchar(max);
SET @str = 'DECLARE @list [dbo].[StringList]; INSERT INTO @list VALUES '

-- Add all the values we want to the string. This would be a loop in C++.
SELECT @str = @str + '(''' + StringValue + '''),' FROM @list

-- Remove the trailing comma so the query is valid sql.
SET @str = substring(@str, 1, len(@str)-1)

-- Add a select to test the string.
SET @str = @str + '; SELECT * FROM @list;'

-- Execute the string and see we've pass the table correctly.
EXEC(@str)

7

SQL Server 2016+ හි තවත් හැකියාවක් වන්නේ OPENJSON ශ්‍රිතය .

මෙම ප්‍රවේශය OPENJSON හි බ්ලොග් කර ඇත - අයිඩී ලැයිස්තුවෙන් පේළි තෝරා ගැනීමට හොඳම ක්‍රමයකි .

සම්පුර්ණ වැඩ කළ උදාහරණයක් පහතින්

CREATE TABLE dbo.Tags
  (
     Name  VARCHAR(50),
     Count INT
  )

INSERT INTO dbo.Tags
VALUES      ('VB',982), ('ruby',1306), ('rails',1478), ('scruffy',1), ('C#',1784)

GO

CREATE PROC dbo.SomeProc
@Tags VARCHAR(MAX)
AS
SELECT T.*
FROM   dbo.Tags T
WHERE  T.Name IN (SELECT J.Value COLLATE Latin1_General_CI_AS
                  FROM   OPENJSON(CONCAT('[', @Tags, ']')) J)
ORDER  BY T.Count DESC

GO

EXEC dbo.SomeProc @Tags = '"ruby","rails","scruffy","rubyonrails"'

DROP TABLE dbo.Tags 

7

මෙන්න තවත් විකල්පයක්. ගබඩා කළ ක්‍රියා පටිපාටියට නූල් පරාමිතියක් ලෙස කොමාවකින් වෙන් කරන ලද ලැයිස්තුවක් යවන්න:

CREATE PROCEDURE [dbo].[sp_myproc]
    @UnitList varchar(MAX) = '1,2,3'
AS
select column from table
where ph.UnitID in (select * from CsvToInt(@UnitList))

සහ කාර්යය:

CREATE Function [dbo].[CsvToInt] ( @Array varchar(MAX))
returns @IntTable table
(IntValue int)
AS
begin
    declare @separator char(1)
    set @separator = ','
    declare @separator_position int
    declare @array_value varchar(MAX)

    set @array = @array + ','

    while patindex('%,%' , @array) <> 0
    begin

        select @separator_position = patindex('%,%' , @array)
        select @array_value = left(@array, @separator_position - 1)

        Insert @IntTable
        Values (Cast(@array_value as int))
        select @array = stuff(@array, 1, @separator_position, '')
    end
    return
end

6

යූඩීඑෆ්, එක්ස්එම්එල් අවශ්‍ය නොවන පිළිතුරක් මා සතුව ඇත.

ඔබට සැබවින්ම අවශ්‍ය වන්නේ නූල මේසයක් බවට පරිවර්තනය කිරීමේ ක්‍රමයක් පමණි.

මෙය පුනරාවර්තන CTE සමඟ හෝ අංක වගුවක් සහිත විමසුමකින් කළ හැකිය (හෝ Master..spt_value)

මෙන්න CTE අනුවාදය.

DECLARE @InputString varchar(8000) = 'ruby,rails,scruffy,rubyonrails'

SELECT @InputString = @InputString + ','

;WITH RecursiveCSV(x,y) 
AS 
(
    SELECT 
        x = SUBSTRING(@InputString,0,CHARINDEX(',',@InputString,0)),
        y = SUBSTRING(@InputString,CHARINDEX(',',@InputString,0)+1,LEN(@InputString))
    UNION ALL
    SELECT 
        x = SUBSTRING(y,0,CHARINDEX(',',y,0)),
        y = SUBSTRING(y,CHARINDEX(',',y,0)+1,LEN(y))
    FROM 
        RecursiveCSV 
    WHERE
        SUBSTRING(y,CHARINDEX(',',y,0)+1,LEN(y)) <> '' OR 
        SUBSTRING(y,0,CHARINDEX(',',y,0)) <> ''
)
SELECT
    * 
FROM 
    Tags
WHERE 
    Name IN (select x FROM RecursiveCSV)
OPTION (MAXRECURSION 32767);

6

ඉහළ ඡන්දය දුන් පිළිතුරේ වඩාත් සංක්ෂිප්ත අනුවාදයක් මම භාවිතා කරමි :

List<SqlParameter> parameters = tags.Select((s, i) => new SqlParameter("@tag" + i.ToString(), SqlDbType.NVarChar(50)) { Value = s}).ToList();

var whereCondition = string.Format("tags in ({0})", String.Join(",",parameters.Select(s => s.ParameterName)));

එය ටැග් පරාමිතීන් හරහා දෙවරක් ලූප කරයි; නමුත් එය බොහෝ විට වැදගත් නොවේ (එය ඔබගේ බාධකයක් නොවනු ඇත; එසේ නම්, ලූපය ඉවත් කරන්න).

ඔබ කාර්ය සාධනය ගැන සැබවින්ම උනන්දුවක් දක්වන්නේ නම් සහ දෙවරක් ලූපය හරහා නැවත බැලීමට අකමැති නම්, මෙන්න අඩු ලස්සන අනුවාදයක්:

var parameters = new List<SqlParameter>();
var paramNames = new List<string>();
for (var i = 0; i < tags.Length; i++)  
{
    var paramName = "@tag" + i;

    //Include size and set value explicitly (not AddWithValue)
    //Because SQL Server may use an implicit conversion if it doesn't know
    //the actual size.
    var p = new SqlParameter(paramName, SqlDbType.NVarChar(50) { Value = tags[i]; } 
    paramNames.Add(paramName);
    parameters.Add(p);
}

var inClause = string.Join(",", paramNames);

5

මෙන්න මෙම ගැටලුවට තවත් පිළිතුරක්.

(නව අනුවාදය 6/4/13 දින පළ කරන ලදි).

    private static DataSet GetDataSet(SqlConnectionStringBuilder scsb, string strSql, params object[] pars)
    {
        var ds = new DataSet();
        using (var sqlConn = new SqlConnection(scsb.ConnectionString))
        {
            var sqlParameters = new List<SqlParameter>();
            var replacementStrings = new Dictionary<string, string>();
            if (pars != null)
            {
                for (int i = 0; i < pars.Length; i++)
                {
                    if (pars[i] is IEnumerable<object>)
                    {
                        List<object> enumerable = (pars[i] as IEnumerable<object>).ToList();
                        replacementStrings.Add("@" + i, String.Join(",", enumerable.Select((value, pos) => String.Format("@_{0}_{1}", i, pos))));
                        sqlParameters.AddRange(enumerable.Select((value, pos) => new SqlParameter(String.Format("@_{0}_{1}", i, pos), value ?? DBNull.Value)).ToArray());
                    }
                    else
                    {
                        sqlParameters.Add(new SqlParameter(String.Format("@{0}", i), pars[i] ?? DBNull.Value));
                    }
                }
            }
            strSql = replacementStrings.Aggregate(strSql, (current, replacementString) => current.Replace(replacementString.Key, replacementString.Value));
            using (var sqlCommand = new SqlCommand(strSql, sqlConn))
            {
                if (pars != null)
                {
                    sqlCommand.Parameters.AddRange(sqlParameters.ToArray());
                }
                else
                {
                    //Fail-safe, just in case a user intends to pass a single null parameter
                    sqlCommand.Parameters.Add(new SqlParameter("@0", DBNull.Value));
                }
                using (var sqlDataAdapter = new SqlDataAdapter(sqlCommand))
                {
                    sqlDataAdapter.Fill(ds);
                }
            }
        }
        return ds;
    }

චියර්ස්.


4

එකම ජයග්‍රාහී පියවර වන්නේ ක්‍රීඩා කිරීම නොවේ.

ඔබට අසීමිත විචල්‍යතාවයක් නොමැත. සීමිත විචල්‍යතාවයක් පමණි.

SQL හි ඔබට මෙවැනි වගන්තියක් ඇත:

and ( {1}==0 or b.CompanyId in ({2},{3},{4},{5},{6}) )

සී # කේතයේ ඔබ මේ වගේ දෙයක් කරනවා:

  int origCount = idList.Count;
  if (origCount > 5) {
    throw new Exception("You may only specify up to five originators to filter on.");
  }
  while (idList.Count < 5) { idList.Add(-1); }  // -1 is an impossible value
  return ExecuteQuery<PublishDate>(getValuesInListSQL, 
               origCount,   
               idList[0], idList[1], idList[2], idList[3], idList[4]);

එබැවින් මූලික වශයෙන් ගණන් කිරීම 0 නම් පෙරනයක් නොමැති අතර සියල්ල හරහා ගමන් කරයි. ගණන් කිරීම 0 ට වඩා වැඩි නම්, එම අගය ලැයිස්තුවේ තිබිය යුතුය, නමුත් කළ නොහැකි අගයන් සහිත ලැයිස්තුව පහක් දක්වා විහිදී ඇත (එවිට SQL තවමත් අර්ථවත් කරයි)

සමහර විට කොර ද්‍රාවණය ඇත්ත වශයෙන්ම ක්‍රියාත්මක වන එකම ක්‍රමයයි.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.