LinqでSQL Like%を行う方法は?


385

Linqに変換しようとしているSQLのプロシージャがあります。

SELECT O.Id, O.Name as Organization
FROM Organizations O
JOIN OrganizationsHierarchy OH ON O.Id=OH.OrganizationsId
where OH.Hierarchy like '%/12/%'

私が最も気になる行は次のとおりです。

where OH.Hierarchy like '%/12/%'

たとえば、/ 1/3/12 /などの階層を格納する列があるので、%/ 12 /%を使用して検索します。

私の質問は、パーセント記号を使用することに相当するLinqまたは.NETは何ですか?


1
あなたの質問には、少なくともlike-operatorタグ5への投票があります。sql-like同義語として提案するようにお願いできますか?
Kermit

回答:


550
.Where(oh => oh.Hierarchy.Contains("/12/"))

.StartsWith()またはを使用することもできます.EndsWith()


4
StartsWith()またはEndsWith()を使用すると、クエリが起動されますか?つまり、コードはクエリに変換されますか、それともDBから取得した後、オブジェクトで結果がフィルタリングされますか?
初心者

5
いいえ。StartsWith()およびEndsWith()は述語/フィルターの一部です。実行は引き続き延期されます。
andleer 2012

2
NullReferenceExceptionを取得しようとしました:オブジェクト参照がオブジェクトのインスタンスに設定されていません。したがって、私の場合、a.Address1.StartsWith(Address1)でa.Address1がnullの場合は気に入らない
MikeT

11
StartsWith("abc")変換されるLIKE 'abc%'EndsWith("abc")にcnovertedされるLIKE '%abc'
Simon_Weaver

20
これが文字の使用例で機能しない理由を理解できなかったので、私の愚かさに気づきました...大文字と小文字.ToLower().Contains()を無視したい場合は、忘れないでください。もちろん、これが必要かどうかは、大文字と小文字を区別しない照合を使用してDBからLIKEを模倣するかどうかによって異なります。
アダム騎士

251

これを使って:

from c in dc.Organization
where SqlMethods.Like(c.Hierarchy, "%/12/%")
select *;

22
これは、likeコマンドによって提供されるより複雑なパターンマッチングを使用する場合に非常に役立ちます。たとえば、任意の2つの数値(12ではなく)をチェックする場合は、次の式を使用できます。SqlMethods.Like(c.Hierarchy、 "%/ [0-9] [0-9] /%")また、こちらをご覧くださいmsdn.microsoft.com/en-us/library/aa933232(SQL.80).aspx
viggity

これは、パワーユーザーが高価なイニシャル%を先頭に付加できるようにする場合にも非常に役立ちます。StartsWithまたはContainsを使用してもパワーユーザーにこのような柔軟性はありません
Simon_Weaver

8
SqlMethods「ドット表記」をどのように使用しますか?
dan-gph 2014

12
System.Data.Linq.SqlClient名前空間を含める必要があることに注意してください。
johna 14

1
System.Data.Linqは追加できますが、System.Data.Linq.SqlClientが見つかりませんでした。非推奨ですか?
BurakKarakuş15年

41

私はあなたがLinq-to-SQL *を使用していると想定しています(以下の注を参照)。その場合は、string.Contains、string.StartsWith、およびstring.EndsWithを使用して、SQL LIKE演算子を使用するSQLを生成します。

from o in dc.Organization
join oh in dc.OrganizationsHierarchy on o.Id equals oh.OrganizationsId
where oh.Hierarchy.Contains(@"/12/")
select new { o.Id, o.Name }

または

from o in dc.Organization
where o.OrganizationsHierarchy.Hierarchy.Contains(@"/12/")
select new { o.Id, o.Name }

注: * = .net 3.5でADO.Net Entity Framework(EF / L2E)を使用している場合、Linq-to-SQLと同じ変換を行わないことに注意してください。L2Sは適切な変換を行いますが、L2E v1(3.5)はt-sql式に変換されます。これにより、where句または結合フィルターに別のより良い弁別子がない限り、照会しているテーブルで全テーブルスキャンが強制されます。
更新:これはEF / L2E v4(.net 4.0)で修正されているため、L2Sと同じようにSQL LIKEが生成されます。


@記号で文字列をエスケープする必要はありませんが、これは従うべき良い規則にすぎないかもしれません。
andleer

27

VB.NETを使用している場合、答えは「*」になります。where句は次のようになります...

Where OH.Hierarchy Like '*/12/*'

注:「*」は0個以上の文字に一致します。Like演算子のmsdn記事を次に示します。


VB LikeオペレーターはL2S呼び出しに変換されますか?(私には
わかり

8
はい、VB Like演算子は、LINQクエリ式で使用すると、SQLバージョンのlikeに変換されます。また、VB Like演算子はクエリ式に限定されません。
robertz 2009年

1
私はそれがLINQオペレーションの外に存在しているのを見ました。いい物。+1
andleer 2009年

9

indexOfも私にとってはうまくいきます

var result = from c in SampleList
where c.LongName.IndexOf(SearchQuery) >= 0
select c;

1
これは受け入れられる答えになるはずです。IndexOfは、SQLではCHARINDEXに変換されます。これはおそらくLIKEよりも高速かもしれません。しかし、それとは別に、「%some%thing%」のような検索クエリを作成する可能性があります。「何か」を「もの」の前に配置する必要がある場所。これは、Containsでは実行できません。
Ruard van Elburg 2017

必要な答えが8歳で、受け入れられた答えの下にいくつかの層を押し込んでいるときに、私はそれを愛しています。簡単に言えば、これは機能しましたが、.Contains(@ "/ 12 /")および他の同様の回答では機能しませんでした。とても有難い!
IdusOrtus

4

そのようなコードを使用する

try
{
    using (DatosDataContext dtc = new DatosDataContext())
    {
        var query = from pe in dtc.Personal_Hgo
                    where SqlMethods.Like(pe.nombre, "%" + txtNombre.Text + "%")
                    select new
                    {
                        pe.numero
                        ,
                        pe.nombre
                    };
        dgvDatos.DataSource = query.ToList();
    }
}
catch (Exception ex)
{
    string mensaje = ex.Message;
}

4

.NETコアに EF.Functions.Like


これを使用してOPの問題を解決する方法を説明できますか?
ロバートコロンビア

つまり、LPからの回答を参照してください。これは、SqlMethods.Likeのコアバージョンにすぎません
kofifus

この回答には、この関数の使用方法の実用的な例が含まれている必要があります。
FoxDeploy

3

数値文字列と一致しない場合は、常に一般的なケースがあるとよいでしょう。

.Where(oh => oh.Hierarchy.ToUpper().Contains(mySearchString.ToUpper()))

2

私はいつもこれをします:

from h in OH
where h.Hierarchy.Contains("/12/")
select h

私はlikeステートメントを使用しないことを知っていますが、これはlikeステートメントを使用したクエリに変換されるため、バックグラウンドで正常に機能します。


あなたの回答は、受け入れられた回答(7年前に回答されたもの)や他の回答とどう違いますか?それはどんな価値を追加しますか?
David FerenczyRogožan16年

1
@DawidFerenczyこの回答は「from foo in bar」クエリ構文で機能しますが、受け入れられたものは機能しません。
nasch

1

これを試してください、これは私にとってはうまくいきます

from record in context.Organization where record.Hierarchy.Contains(12) select record;


0

ContainsはLinqで使用され、LikeがSQLで使用されるのと同じです。

string _search="/12/";

。。。

.Where(s => s.Hierarchy.Contains(_search))

次のようにLinqでSQLスクリプトを記述できます。

 var result= Organizations.Join(OrganizationsHierarchy.Where(s=>s.Hierarchy.Contains("/12/")),s=>s.Id,s=>s.OrganizationsId,(org,orgH)=>new {org,orgH});

0

LINQの "SQL Like"メソッドへの道を模索している私のように、このようにひっくり返った人々のために、私は非常にうまく機能しているものを持っています。

列の照合順序を変更する方法でデータベースを変更できない場合があります。そのため、LINQでその方法を見つける必要があります。

SqlFunctions.PatIndex実際のSQL LIKE演算子と同様に機能するヘルパーメソッドwitch を使用しています。

最初に、次のようなものを得るために、検索値ですべての可能な発音区別符号(今学んだ単語)を列挙する必要があります。

déjà     => d[éèêëeÉÈÊËE]j[aàâäAÀÂÄ]
montreal => montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l
montréal => montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l

そして、LINQで例:

var city = "montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l";
var data = (from loc in _context.Locations
                     where SqlFunctions.PatIndex(city, loc.City) > 0
                     select loc.City).ToList();

だから私のニーズのために私はヘルパー/拡張メソッドを書きました

   public static class SqlServerHelper
    {

        private static readonly List<KeyValuePair<string, string>> Diacritics = new List<KeyValuePair<string, string>>()
        {
            new KeyValuePair<string, string>("A", "aàâäAÀÂÄ"),
            new KeyValuePair<string, string>("E", "éèêëeÉÈÊËE"),
            new KeyValuePair<string, string>("U", "uûüùUÛÜÙ"),
            new KeyValuePair<string, string>("C", "cçCÇ"),
            new KeyValuePair<string, string>("I", "iîïIÎÏ"),
            new KeyValuePair<string, string>("O", "ôöÔÖ"),
            new KeyValuePair<string, string>("Y", "YŸÝýyÿ")
        };

        public static string EnumarateDiacritics(this string stringToDiatritics)
        {
            if (string.IsNullOrEmpty(stringToDiatritics.Trim()))
                return stringToDiatritics;

            var diacriticChecked = string.Empty;

            foreach (var c in stringToDiatritics.ToCharArray())
            {
                var diac = Diacritics.FirstOrDefault(o => o.Value.ToCharArray().Contains(c));
                if (string.IsNullOrEmpty(diac.Key))
                    continue;

                //Prevent from doing same letter/Diacritic more than one time
                if (diacriticChecked.Contains(diac.Key))
                    continue;

                diacriticChecked += diac.Key;

                stringToDiatritics = stringToDiatritics.Replace(c.ToString(), "[" + diac.Value + "]");
            }

            stringToDiatritics = "%" + stringToDiatritics + "%";
            return stringToDiatritics;
        }
    }

この方法を強化する提案がありましたら、お聞かせください。


あなたの例は基本的に自家製のアクセントを区別しない照合です。私はかつて、適切な照合が自動的に行うことを実現するために、すべてのクエリがフィルターを通過するプロジェクトに対処する必要がありました。通常はより良いアプローチについては、stackoverflow.com / a / 2461550/1736944をご覧ください。適切と見なされるように、データベース、テーブル、フィールドに適切な照合を割り当てます。(適切な照合を行わずに作業することは純粋な拷問です)
9Rune5

0

遅いですが、SQL Likeスタイルのワイルドカードを使用して文字列比較を実行できるように、これを一緒に投げました:

public static class StringLikeExtensions
{
    /// <summary>
    /// Tests a string to be Like another string containing SQL Like style wildcards
    /// </summary>
    /// <param name="value">string to be searched</param>
    /// <param name="searchString">the search string containing wildcards</param>
    /// <returns>value.Like(searchString)</returns>
    /// <example>value.Like("a")</example>
    /// <example>value.Like("a%")</example>
    /// <example>value.Like("%b")</example>
    /// <example>value.Like("a%b")</example>
    /// <example>value.Like("a%b%c")</example>
    /// <remarks>base author -- Ruard van Elburg from StackOverflow, modifications by dvn</remarks>
    /// <remarks>converted to a String extension by sja</remarks>
    /// <seealso cref="/programming/1040380/wildcard-search-for-linq"/>
    public static bool Like(this String value, string searchString)
    {
        bool result = false;

        var likeParts = searchString.Split(new char[] { '%' });

        for (int i = 0; i < likeParts.Length; i++)
        {
            if (likeParts[i] == String.Empty)
            {
                continue;   // "a%"
            }

            if (i == 0)
            {
                if (likeParts.Length == 1) // "a"
                {
                    result = value.Equals(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
                else // "a%" or "a%b"
                {
                    result = value.StartsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
            }
            else if (i == likeParts.Length - 1) // "a%b" or "%b"
            {
                result &= value.EndsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
            }
            else // "a%b%c"
            {
                int current = value.IndexOf(likeParts[i], StringComparison.OrdinalIgnoreCase);
                int previous = value.IndexOf(likeParts[i - 1], StringComparison.OrdinalIgnoreCase);
                result &= previous < current;
            }
        }

        return result;
    }

    /// <summary>
    /// Tests a string containing SQL Like style wildcards to be ReverseLike another string 
    /// </summary>
    /// <param name="value">search string containing wildcards</param>
    /// <param name="compareString">string to be compared</param>
    /// <returns>value.ReverseLike(compareString)</returns>
    /// <example>value.ReverseLike("a")</example>
    /// <example>value.ReverseLike("abc")</example>
    /// <example>value.ReverseLike("ab")</example>
    /// <example>value.ReverseLike("axb")</example>
    /// <example>value.ReverseLike("axbyc")</example>
    /// <remarks>reversed logic of Like String extension</remarks>
    public static bool ReverseLike(this String value, string compareString)
    {
        bool result = false;

        var likeParts = value.Split(new char[] {'%'});

        for (int i = 0; i < likeParts.Length; i++)
        {
            if (likeParts[i] == String.Empty)
            {
                continue;   // "a%"
            }

            if (i == 0)
            {
                if (likeParts.Length == 1) // "a"
                {
                    result = compareString.Equals(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
                else // "a%" or "a%b"
                {
                    result = compareString.StartsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
            }
            else if (i == likeParts.Length - 1) // "a%b" or "%b"
            {
                result &= compareString.EndsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
            }
            else // "a%b%c"
            {
                int current = compareString.IndexOf(likeParts[i], StringComparison.OrdinalIgnoreCase);
                int previous = compareString.IndexOf(likeParts[i - 1], StringComparison.OrdinalIgnoreCase);
                result &= previous < current;
            }
        }

        return result;
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.