programing

Linq에서 SQL Like %를 수행하는 방법은 무엇입니까?

i4 2023. 5. 21. 10:57
반응형

Linq에서 SQL Like %를 수행하는 방법은 무엇입니까?

SQL에 Linkq로 변환하려는 프로시저가 있습니다.

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은 무엇입니까?

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

사용할 수도 있습니다..StartsWith()또는.EndsWith().

사용:

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

Link-to-SQL*을 사용하고 있다고 가정합니다(아래 참고 참조).그렇다면 문자열을 사용합니다.포함, 문자열.시작: , 및 문자열.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)를 사용하는 경우, Linkq-to-SQL과 동일한 변환을 수행하지 않습니다.L2S가 적절한 변환을 수행하지만, L2E v1(3.5)은 where 절 또는 조인 필터에 더 나은 식별자가 없는 한 쿼리하는 테이블에서 전체 테이블 검색을 강제로 수행하는 t-sql 식으로 변환됩니다.
업데이트: EF/L2E v4(.net 4.0)에서 수정되었으므로 L2S와 마찬가지로 SQL LIKE를 생성합니다.

VB.NET을 사용하는 경우 "*"가 정답입니다.여기 당신의 어디 조항이 어떻게 보일까요?

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

참고: "*"는 0자 이상과 일치합니다.좋아요 연산자에 대한 msdn 기사입니다.

저도 잘 맞는 색인입니다.

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

.NET 코어는 이제EF.Functions.Like

  var isMatch = EF.Functions.Like(stringThatMightMatch, pattern);

해당 코드 사용

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;
}

숫자 문자열이 일치하지 않는 경우에는 항상 일반적인 대소문자를 사용하는 것이 좋습니다.

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

항상 하는 일:

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

나는 내가 유사한 문장을 사용하지 않는다는 것을 알고 있지만 배경에서 잘 작동합니다. 이것은 유사한 문장을 가진 질의로 번역됩니다.

System.Data.Linq.SqlClient.SqlMethods.Like("mystring", "%string")

이것을 사용해 보세요, 이것은 저에게 잘 맞습니다.

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

LINQ에서 "SQL Like" 방법을 찾고 있는 저처럼 여기에 있는 사람들을 위해, 저는 매우 잘 작동하는 무언가를 가지고 있습니다.

열 조합을 변경하기 위해 데이터베이스를 변경할 수 없는 경우입니다.그래서 LINQ에서 방법을 찾아야 합니다.

실제 SQL LIKE 연산자와 유사한 동작을 하는 도우미 방식을 사용하고 있습니다.

먼저 다음과 같은 것을 얻으려면 검색 값에 가능한 모든 분음 부호(내가 방금 배운 단어)를 열거해야 합니다.

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;
        }
    }

이 방법을 개선할 수 있는 의견이 있으시면 언제든지 말씀해 드리겠습니다.

훨씬 늦었지만 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="https://stackoverflow.com/questions/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;
    }
}

Like가 SQL에서 사용되는 처럼 Contains는 Linq에서 사용됩니다.

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});

Unit Testing과 같은 클라이언트 작업에 LIKE 기능이 필요한 경우 CodeProject에 의한 이 방법은 와일드카드의 동작을 잘 모방합니다.

@Steve Ackerman의 대답과 약간 비슷하지만, 더 포괄적입니다.

/// Published on CodeProject: http://www.codeproject.com/Articles/
///         608266/A-Csharp-LIKE-implementation-that-mimics-SQL-LIKE
/// </remarks>
public static bool Like(this string s, string match, bool CaseInsensitive = true)
{
    //Nothing matches a null mask or null input string
    if (match == null || s == null)
        return false;
    //Null strings are treated as empty and get checked against the mask.
    //If checking is case-insensitive we convert to uppercase to facilitate this.
    if (CaseInsensitive)
    {
        s = s.ToUpperInvariant();
        match = match.ToUpperInvariant();
    }
    //Keeps track of our position in the primary string - s.
    int j = 0;
    //Used to keep track of multi-character wildcards.
    bool matchanymulti = false;
    //Used to keep track of multiple possibility character masks.
    string multicharmask = null;
    bool inversemulticharmask = false;
    for (int i = 0; i < match.Length; i++)
    {
        //If this is the last character of the mask and its a % or * we are done
        if (i == match.Length - 1 && (match[i] == '%' || match[i] == '*'))
            return true;
        //A direct character match allows us to proceed.
        var charcheck = true;
        //Backslash acts as an escape character.  If we encounter it, proceed
        //to the next character.
        if (match[i] == '\\')
        {
            i++;
            if (i == match.Length)
                i--;
        }
        else
        {
            //If this is a wildcard mask we flag it and proceed with the next character
            //in the mask.
            if (match[i] == '%' || match[i] == '*')
            {
                matchanymulti = true;
                continue;
            }
            //If this is a single character wildcard advance one character.
            if (match[i] == '_')
            {
                //If there is no character to advance we did not find a match.
                if (j == s.Length)
                    return false;
                j++;
                continue;
            }
            if (match[i] == '[')
            {
                var endbracketidx = match.IndexOf(']', i);
                //Get the characters to check for.
                multicharmask = match.Substring(i + 1, endbracketidx - i - 1);
                //Check for inversed masks
                inversemulticharmask = multicharmask.StartsWith("^");
                //Remove the inversed mask character
                if (inversemulticharmask)
                    multicharmask = multicharmask.Remove(0, 1);
                //Unescape \^ to ^
                multicharmask = multicharmask.Replace("\\^", "^");
                
                //Prevent direct character checking of the next mask character
                //and advance to the next mask character.
                charcheck = false;
                i = endbracketidx;
                //Detect and expand character ranges
                if (multicharmask.Length == 3 && multicharmask[1] == '-')
                {
                    var newmask = "";
                    var first = multicharmask[0];
                    var last = multicharmask[2];
                    if (last < first)
                    {
                        first = last;
                        last = multicharmask[0];
                    }
                    var c = first;
                    while (c <= last)
                    {
                        newmask += c;
                        c++;
                    }
                    multicharmask = newmask;
                }
                //If the mask is invalid we cannot find a mask for it.
                if (endbracketidx == -1)
                    return false;
            }
        }
        //Keep track of match finding for this character of the mask.
        var matched = false;
        while (j < s.Length)
        {
            //This character matches, move on.
            if (charcheck && s[j] == match[i])
            {
                j++;
                matched = true;
                break;
            }
            //If we need to check for multiple charaters to do.
            if (multicharmask != null)
            {
                var ismatch = multicharmask.Contains(s[j]);
                //If this was an inverted mask and we match fail the check for this string.
                //If this was not an inverted mask check and we did not match fail for this string.
                if (inversemulticharmask && ismatch ||
                    !inversemulticharmask && !ismatch)
                {
                    //If we have a wildcard preceding us we ignore this failure
                    //and continue checking.
                    if (matchanymulti)
                    {
                        j++;
                        continue;
                    }
                    return false;
                }
                j++;
                matched = true;
                //Consumse our mask.
                multicharmask = null;
                break;
            }
            //We are in an multiple any-character mask, proceed to the next character.
            if (matchanymulti)
            {
                j++;
                continue;
            }
            break;
        }
        //We've found a match - proceed.
        if (matched)
        {
            matchanymulti = false;
            continue;
        }

        //If no match our mask fails
        return false;
    }
    //Some characters are left - our mask check fails.
    if (j < s.Length)
        return false;
    //We've processed everything - this is a match.
    return true;
} 

언급URL : https://stackoverflow.com/questions/835790/how-to-do-sql-like-in-linq

반응형