วิธีทำ SQL Like% ใน Linq


385

ฉันมีขั้นตอนใน SQL ที่ฉันพยายามเปลี่ยนเป็น Linq:

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
คำถามของคุณมี5คะแนนอย่างน้อยสำหรับแท็กตัวดำเนินการเหมือนกัน ฉันขอความกรุณาให้คุณแนะนำsql-likeเป็นคำเหมือนได้ไหม
มิต

คำตอบ:


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

นอกจากนี้คุณยังสามารถใช้หรือ.StartsWith().EndsWith()


4
การใช้ StartsWith () หรือ EndsWith () จะเริ่มการสืบค้นหรือไม่ ฉันหมายถึงรหัสจะถูกแปลเป็นแบบสอบถามหรือผลลัพธ์จะถูกกรองในวัตถุหลังจากดึงจาก DB หรือไม่
สามเณร

5
เลขที่ StartsWith () และ EndsWith () เป็นส่วนหนึ่งของเพรดิเคต / ตัวกรอง การดำเนินการยังคงถูกเลื่อนออกไป
andleer

2
พยายามที่ได้ NullReferenceException: การอ้างอิงวัตถุไม่ได้ตั้งค่าเป็นอินสแตนซ์ของวัตถุ ดังนั้นจึงไม่ชอบเมื่อในกรณีของฉัน a.Address1.StartsWith (ที่อยู่ 1) และ a.Address1 เป็นโมฆะ
MikeT

11
StartsWith("abc")รับการแปลงเป็นLIKE 'abc%'และEndsWith("abc")เป็น cnoverted ไปLIKE '%abc'
Simon_Weaver

20
ไม่ทราบสาเหตุว่าทำไมจึงไม่สามารถใช้งานได้กับตัวอักษรจากนั้นตระหนักถึงความโง่เขลาของฉัน ... อย่าลืม.ToLower().Contains()ฯลฯ หากคุณไม่สนใจกรณี ไม่ว่าคุณจะต้องการสิ่งนี้หรือไม่นั้นขึ้นอยู่กับว่าคุณพยายามเลียนแบบ LIKE จากฐานข้อมูลด้วยการเปรียบเทียบแบบตัวเล็กและตัวพิมพ์เล็กหรือไม่
อดัมอัศวิน

251

ใช้สิ่งนี้:

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

22
สิ่งนี้มีประโยชน์จริง ๆ ถ้าคุณต้องการใช้การจับคู่รูปแบบที่ซับซ้อนยิ่งขึ้นซึ่งจัดเตรียมโดยคำสั่ง like ตัวอย่างเช่นหากคุณต้องการตรวจสอบสองตัวเลขใด ๆ (แทน 12) คุณสามารถใช้นิพจน์นี้: SqlMethods.Like (c.Hierarchy "% / [0-9] [0-9] /%") ดูmsdn.microsoft.com/en-us/library/aa933232(SQL.80).aspx
viggity

สิ่งนี้ยังมีประโยชน์มากหากคุณต้องการให้ผู้ใช้ระดับสูงสามารถใช้% เริ่มต้นที่มีราคาแพงได้ด้วยตัวเองโดยที่การใช้ StartsWith หรือมีไม่ได้ให้ความยืดหยุ่นแก่ผู้ใช้ระดับสูง
Simon_Weaver

8
คุณใช้งานSqlMethodsโดยใช้ "dot notation" ได้อย่างไร?
dan-gph

12
โปรดทราบว่าคุณต้องรวมSystem.Data.Linq.SqlClientเนมสเปซ
johna

1
ฉันหา System.Data.Linq.SqlClient ไม่พบแม้ว่าฉันสามารถเพิ่ม System.Data.Linq เลิกหรือไม่
Burak Karakuş

41

ฉันสมมติว่าคุณกำลังใช้ Linq-to-SQL * (ดูหมายเหตุด้านล่าง) ถ้าเป็นเช่นนั้นให้ใช้ string.Contains, string.StartsWith และ string.EndsWith เพื่อสร้าง SQL ที่ใช้ตัวดำเนินการ SQL LIKE

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 }

หมายเหตุ: * = หากคุณใช้ ADO.Net Entity Framework (EF / L2E) ใน. net 3.5 โปรดทราบว่าจะไม่ทำการแปลแบบเดียวกับ Linq-to-SQL แม้ว่า L2S จะทำการแปลที่ถูกต้อง แต่ L2E v1 (3.5) จะแปลเป็นนิพจน์ t-sql ที่จะบังคับให้สแกนตารางเต็มบนตารางที่คุณทำการสืบค้นเว้นแต่จะมี discriminator อื่นที่ดีกว่าในส่วนคำสั่งหรือเข้าร่วมตัวกรอง
อัปเดต:แก้ไขใน EF / L2E v4 (.net 4.0) ดังนั้นมันจะสร้าง SQL LIKE เช่นเดียวกับ L2S


ไม่จำเป็นต้องหลบหนีสายของคุณด้วย@สัญญาณ แต่ฉันรู้ว่านี่อาจเป็นวิธีการที่ดีในการติดตาม
andleer

27

ถ้าคุณใช้ VB.NET คำตอบก็คือ "*" นี่คือสิ่งที่ประโยคของคุณจะมีลักษณะ ...

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

หมายเหตุ: "*" ตรงกับศูนย์หรือมากกว่าตัวละคร นี่คือบทความ MSDN สำหรับผู้ประกอบการเช่นเดียวกับ


ตัวดำเนินการ VB Like แปลเป็นการโทร L2S หรือไม่ (ฉันไม่มีความคิด)
andleer

8
ใช่ตัวดำเนินการ VB Like ถูกแปลเป็นเวอร์ชั่น SQL ของ Like เมื่อใช้ในนิพจน์แบบสอบถาม LINQ นอกจากนี้ตัวดำเนินการ VB Like ไม่ได้ จำกัด อยู่ที่นิพจน์แบบสอบถาม
robertz

1
ฉันเห็นว่ามันมีอยู่นอกการดำเนินงานของ LINQ สิ่งที่ดี. +1
andleer

9

indexOf ก็ใช้ได้สำหรับฉันเช่นกัน

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

1
นี่ควรเป็นคำตอบที่ยอมรับได้ IndexOf แปลเป็น CHARINDEX ใน sql สิ่งนี้อาจเร็วกว่า LIKE แต่นอกจากนั้นมันยังให้โอกาสในการสร้างคำค้นหาเช่น '% some%%%' ในกรณีที่จะต้องอยู่ก่อน 'สิ่งของ' ซึ่งไม่สามารถทำได้ด้วยการมี
Ruard van Elburg

ฉันรักมันเมื่อคำตอบที่ฉันต้องการคืออายุ 8 ขวบและซ่อนไว้หลายชั้นภายใต้คำตอบที่ยอมรับ พูดง่ายๆคือมันใช้งานได้ในขณะที่. Contents (@ "/ 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 ได้หรือไม่?
Robert Columbia

ดูคือคำตอบจาก 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 Ferenczy Rogožan

1
@DawidFerenczy คำตอบนี้ใช้ได้กับไวยากรณ์การสืบค้น "from foo in bar" และคำตอบที่ยอมรับไม่ได้
nasch

1

ลองนี่ใช้งานได้ดีสำหรับฉัน

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


0

มีใช้ใน Linq, เช่นเดียวกับเหมือนถูกนำมาใช้ใน SQL

string _search="/12/";

. . .

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

คุณสามารถเขียนสคริปต์ SQL ของคุณใน Linq ดังต่อไปนี้:

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

0

สำหรับคนที่เกลือกกลิ้งที่นี่อย่างฉันกำลังมองหาวิธี "SQL Like" ใน LINQ ฉันมีบางสิ่งที่ทำงานได้ดีมาก

ฉันอยู่ในกรณีที่ฉันไม่สามารถแก้ไขฐานข้อมูลในทางใดทางหนึ่งเพื่อเปลี่ยนการเรียงคอลัมน์ ดังนั้นฉันจะหาวิธีใน LINQ ของฉันที่จะทำ

ฉันใช้วิธีตัวช่วยSqlFunctions.PatIndexแม่มดทำหน้าที่คล้ายกับตัวดำเนินการ 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;
        }
    }

หากคุณมีข้อเสนอแนะเพื่อปรับปรุงวิธีการนี้ฉันจะได้โปรดฟังคุณ


ตัวอย่างของคุณนั้นเป็นเพียงการเปรียบเทียบความรู้สึกที่ไม่คุ้นเคยของโฮมบรูว์ ฉันเคยต้องจัดการกับโครงการที่แต่ละแบบสอบถามผ่านตัวกรองเพื่อให้ได้สิ่งที่การเปรียบเทียบที่เหมาะสมจะทำโดยอัตโนมัติ โปรดดูstackoverflow.com/a/2461550/1736944สำหรับวิธีการที่ดีกว่า กำหนดการเปรียบเทียบที่เหมาะสมให้กับฐานข้อมูลตารางและ / หรือฟิลด์ตามความเหมาะสม (การทำงานที่ไม่มีการเรียงที่เหมาะสมคือการทรมานอย่างแท้จริง)
9Rune5

0

ช้าไปหน่อย แต่ฉันรวมมันเข้าด้วยกันเพื่อให้สามารถทำการเปรียบเทียบ String โดยใช้ SQL Like wildcard ของสไตล์:

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.