본문 바로가기

SQL

LINQPad 로 LINQ 문 , SQL 문 연습하기

LINQPad 간단 사용 메모

  • 새 쿼리 → 언어를 C# Program으로 두고 예제 붙여넣기 → 실행.
  • Dump()는 LINQPad 전용 출력 메서드. 컬렉션을 표로 깔끔하게 보여준다.
  • 같은 문제라도 메서드식(Method Syntax)쿼리식(Query Syntax) 둘 다 실습해보는 게 감각 잡는 데 도움이 된다.

Level 1 — 기본 Where / Select

문제 1: 짝수만 필터링

목표: Where 조건 필터링과 Dump() 출력 익히기
데이터

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

정답 – 메서드식

void Main()
{
    int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    var evenNumbers = numbers.Where(n => n % 2 == 0);
    evenNumbers.Dump("짝수");
}

정답 – 쿼리식

void Main()
{
    int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    var evenNumbers =
        from n in numbers
        where n % 2 == 0
        select n;
    evenNumbers.Dump("짝수");
}

예상 출력: 2, 4, 6, 8, 10
SQL로 하면

-- 배열이 아닌 테이블 Numbers(Number)라고 가정
SELECT Number FROM Numbers WHERE Number % 2 = 0;

문제 2: 각 숫자 제곱

목표: Select 로 변환하기

정답 – 메서드식

void Main()
{
    int[] numbers = { 1, 2, 3, 4, 5 };
    var squared = numbers.Select(n => n * n);
    squared.Dump("제곱");
}

정답 – 쿼리식

void Main()
{
    int[] numbers = { 1, 2, 3, 4, 5 };
    var squared =
        from n in numbers
        select n * n;
    squared.Dump("제곱");
}

예상 출력: 1, 4, 9, 16, 25
SQL로 하면

SELECT n * n AS Squared FROM Numbers n;

Level 2 — OrderBy / Select / 조합

문제 3: 길이≥4 이름, 알파벳순 정렬, 대문자화

데이터

string[] names = { "Kim", "Alice", "Tom", "Jessica", "Bob", "Charlie" };

정답 – 메서드식

void Main()
{
    string[] names = { "Kim", "Alice", "Tom", "Jessica", "Bob", "Charlie" };
    var result = names
        .Where(n => n.Length >= 4)
        .OrderBy(n => n)
        .Select(n => n.ToUpper());
    result.Dump("길이>=4, 정렬 후 대문자");
}

정답 – 쿼리식

void Main()
{
    string[] names = { "Kim", "Alice", "Tom", "Jessica", "Bob", "Charlie" };
    var result =
        from n in names
        where n.Length >= 4
        orderby n
        select n.ToUpper();
    result.Dump("길이>=4, 정렬 후 대문자");
}

예상 출력: ALICE, CHARLIE, JESSICA
SQL로 하면

SELECT UPPER(Name)
FROM People
WHERE LEN(Name) >= 4
ORDER BY Name ASC;

문제 4: 홀수 내림차순

데이터

int[] numbers = { 7, 2, 9, 4, 11, 5 };

정답 – 메서드식

void Main()
{
    int[] numbers = { 7, 2, 9, 4, 11, 5 };
    var result = numbers
        .Where(n => n % 2 != 0)
        .OrderByDescending(n => n);
    result.Dump("홀수 내림차순");
}

정답 – 쿼리식

void Main()
{
    int[] numbers = { 7, 2, 9, 4, 11, 5 };
    var result =
        from n in numbers
        where n % 2 != 0
        orderby n descending
        select n;
    result.Dump("홀수 내림차순");
}

예상 출력: 11, 9, 7, 5
SQL로 하면

SELECT n
FROM Numbers
WHERE n % 2 <> 0
ORDER BY n DESC;

Level 3 — GroupBy

문제 5: 학년(Grade)별 그룹화

데이터

var students = new[]
{
    new { Name = "Alice",   Grade = 1 },
    new { Name = "Bob",     Grade = 2 },
    new { Name = "Charlie", Grade = 1 },
    new { Name = "David",   Grade = 3 },
    new { Name = "Eve",     Grade = 2 },
    new { Name = "Frank",   Grade = 3 }
};

정답 – 메서드식

void Main()
{
    var students = new[]
    {
        new { Name = "Alice",   Grade = 1 },
        new { Name = "Bob",     Grade = 2 },
        new { Name = "Charlie", Grade = 1 },
        new { Name = "David",   Grade = 3 },
        new { Name = "Eve",     Grade = 2 },
        new { Name = "Frank",   Grade = 3 }
    };

    var grouped = students.GroupBy(s => s.Grade);

    foreach (var g in grouped)
    {
        Console.WriteLine($"Grade {g.Key}: {string.Join(", ", g.Select(x => x.Name))}");
    }
}

정답 – 쿼리식

void Main()
{
    var students = new[]
    {
        new { Name = "Alice",   Grade = 1 },
        new { Name = "Bob",     Grade = 2 },
        new { Name = "Charlie", Grade = 1 },
        new { Name = "David",   Grade = 3 },
        new { Name = "Eve",     Grade = 2 },
        new { Name = "Frank",   Grade = 3 }
    };

    var grouped =
        from s in students
        group s by s.Grade into g
        select new { Grade = g.Key, Names = g.Select(x => x.Name) };

    foreach (var row in grouped)
    {
        Console.WriteLine($"Grade {row.Grade}: {string.Join(", ", row.Names)}");
    }
}

예상 출력

Grade 1: Alice, Charlie
Grade 2: Bob, Eve
Grade 3: David, Frank

SQL로 하면

SELECT Grade, STRING_AGG(Name, ', ')
FROM Students
GROUP BY Grade;
-- Oracle은 LISTAGG(Name, ', ') WITHIN GROUP (ORDER BY Name)

Level 4 — Join, Distinct, Any/All

문제 6: 내부 조인(Inner Join)으로 사용자와 부서명 묶기

목표: Join 사용, 결과 투영
데이터

var users = new[]
{
    new { Id = 1, Name = "Alice",  DeptId = 10 },
    new { Id = 2, Name = "Bob",    DeptId = 20 },
    new { Id = 3, Name = "Chris",  DeptId = 20 },
    new { Id = 4, Name = "Daisy",  DeptId = 30 },
};
var depts = new[]
{
    new { Id = 10, DeptName = "HR" },
    new { Id = 20, DeptName = "Engineering" },
    new { Id = 30, DeptName = "Sales" }
};

정답 – 메서드식

void Main()
{
    var users = new[]
    {
        new { Id = 1, Name = "Alice",  DeptId = 10 },
        new { Id = 2, Name = "Bob",    DeptId = 20 },
        new { Id = 3, Name = "Chris",  DeptId = 20 },
        new { Id = 4, Name = "Daisy",  DeptId = 30 },
    };
    var depts = new[]
    {
        new { Id = 10, DeptName = "HR" },
        new { Id = 20, DeptName = "Engineering" },
        new { Id = 30, DeptName = "Sales" }
    };

    var q = users.Join(
        depts,
        u => u.DeptId,
        d => d.Id,
        (u, d) => new { u.Name, d.DeptName });

    q.Dump("User x Dept");
}

정답 – 쿼리식

void Main()
{
    var users = new[]
    {
        new { Id = 1, Name = "Alice",  DeptId = 10 },
        new { Id = 2, Name = "Bob",    DeptId = 20 },
        new { Id = 3, Name = "Chris",  DeptId = 20 },
        new { Id = 4, Name = "Daisy",  DeptId = 30 },
    };
    var depts = new[]
    {
        new { Id = 10, DeptName = "HR" },
        new { Id = 20, DeptName = "Engineering" },
        new { Id = 30, DeptName = "Sales" }
    };

    var q =
        from u in users
        join d in depts on u.DeptId equals d.Id
        select new { u.Name, d.DeptName };

    q.Dump("User x Dept");
}

SQL로 하면

SELECT u.Name, d.DeptName
FROM Users u
JOIN Departments d ON u.DeptId = d.Id;

문제 7: 중복 제거 Distinct

목표: Distinct, 복합 키 중복 제거

정답

void Main()
{
    var tags = new[] { "linq", "csharp", "linq", "sql", "sql", "linq" };
    tags.Distinct().Dump("단순 Distinct");

    var rows = new[]
    {
        new { Id = 1, Name = "Alice" },
        new { Id = 1, Name = "Alice" },
        new { Id = 2, Name = "Bob" },
    };
    // 익명형 비교는 참조 동일성이라 Distinct가 기대대로 안 될 수 있음.
    // 키 셀렉터로 그룹화 후 첫 항목 선택 패턴:
    var distinctByIdName = rows
        .GroupBy(x => new { x.Id, x.Name })
        .Select(g => g.First());
    distinctByIdName.Dump("복합키 Distinct");
}

문제 8: Any / All 로 조건 검사

void Main()
{
    int[] numbers = { 2, 4, 6, 8 };

    bool hasOdd = numbers.Any(n => n % 2 == 1);
    bool allEven = numbers.All(n => n % 2 == 0);

    hasOdd.Dump("홀수 하나라도 있나?");
    allEven.Dump("전부 짝수인가?");
}

Level 5 — 집계, 페이징, Null, Left Join 흉내

문제 9: 집계 함수(Sum, Avg, Count, Max/Min)

void Main()
{
    var sales = new[]
    {
        new { UserId = 1, Amount = 100 },
        new { UserId = 1, Amount = 250 },
        new { UserId = 2, Amount = 300 }
    };

    var total = sales.Sum(x => x.Amount);
    var avg   = sales.Average(x => x.Amount);
    var cnt   = sales.Count();
    var max   = sales.Max(x => x.Amount);

    new { total, avg, cnt, max }.Dump("집계");
}

SQL로 하면

SELECT SUM(Amount) AS Total, AVG(Amount) AS Avg, COUNT(*) AS Cnt, MAX(Amount) AS Max
FROM Sales;

문제 10: 페이징 Skip/Take

void Main()
{
    var items = Enumerable.Range(1, 100).ToList();

    int page = 3;   // 3페이지
    int size = 10;  // 페이지당 10개

    var pageItems = items
        .Skip((page - 1) * size)
        .Take(size);

    pageItems.Dump("3페이지(11~30 중 21~30)");
}

SQL로 하면 (SQL Server 2012+)

SELECT *
FROM Items
ORDER BY Id
OFFSET (@page - 1) * @size ROWS
FETCH NEXT @size ROWS ONLY;

문제 11: Null 안전 처리

void Main()
{
    string? maybeNull = null;

    // 널 병합 연산자
    string text = maybeNull ?? "기본값";
    text.Dump("널이면 기본값");

    var users = new[]
    {
        new { Id = 1, Name = (string?)null },
        new { Id = 2, Name = "Alice" }
    };

    users
        .Select(u => new { u.Id, SafeName = u.Name ?? "(이름없음)" })
        .Dump("이름 널 처리");
}

문제 12: Left Join 흉내내기 (GroupJoin + SelectMany(DefaultIfEmpty))

void Main()
{
    var users = new[]
    {
        new { Id = 1, Name = "Alice" },
        new { Id = 2, Name = "Bob" },
        new { Id = 3, Name = "Chris" } // 주문 없음
    };
    var orders = new[]
    {
        new { OrderId = 100, UserId = 1, Item = "Book" },
        new { OrderId = 101, UserId = 1, Item = "Pen" },
        new { OrderId = 200, UserId = 2, Item = "Bag" }
    };

    // 메서드식: GroupJoin + SelectMany + DefaultIfEmpty
    var leftJoin =
        users.GroupJoin(
                orders,
                u => u.Id,
                o => o.UserId,
                (u, os) => new { u, os }
            )
            .SelectMany(
                x => x.os.DefaultIfEmpty(),
                (x, o) => new { x.u.Name, OrderItem = o?.Item }
            );

    leftJoin.Dump("Left Join");
}

쿼리식으로 비슷하게

void Main()
{
    var users = new[]
    {
        new { Id = 1, Name = "Alice" },
        new { Id = 2, Name = "Bob" },
        new { Id = 3, Name = "Chris" }
    };
    var orders = new[]
    {
        new { OrderId = 100, UserId = 1, Item = "Book" },
        new { OrderId = 101, UserId = 1, Item = "Pen" },
        new { OrderId = 200, UserId = 2, Item = "Bag" }
    };

    var leftJoin =
        from u in users
        join o in orders on u.Id equals o.UserId into gj
        from o in gj.DefaultIfEmpty()
        select new { u.Name, OrderItem = o?.Item };

    leftJoin.Dump("Left Join");
}

예상 출력

Alice | Book
Alice | Pen
Bob   | Bag
Chris | null

SQL로 하면

SELECT u.Name, o.Item
FROM Users u
LEFT JOIN Orders o ON u.Id = o.UserId;

보너스 — SelectMany와 평탄화

문제 13: 다중 컬렉션 평탄화

void Main()
{
    var people = new[]
    {
        new { Name = "Alice", Tags = new[] { "csharp", "linq" } },
        new { Name = "Bob",   Tags = new[] { "sql" } }
    };

    var flat =
        people.SelectMany(p => p.Tags, (p, tag) => new { p.Name, Tag = tag });

    flat.Dump("사람 x 태그 평탄화");
}

SQL로 하면
태그를 정규화한 테이블(중간 테이블 PeopleTags)이 있다고 가정.

SELECT p.Name, t.Tag
FROM People p
JOIN PeopleTags t ON p.Id = t.PersonId;

 

  • 메서드식과 쿼리식 둘 다 익혀 두면 문제 해석력이 빨라진다.
  • 컬렉션 출력은 항상 Dump()로 확인. 중간 단계마다 Dump()를 찍어보면 흐름이 보인다.
  • 조인류는 반드시 Inner Join, Left Join 패턴을 각각 연습해둘 것:
    • Inner: Join
    • Left: GroupJoin + SelectMany + DefaultIfEmpty() 또는 쿼리식의 into 그룹과 DefaultIfEmpty()
  • GroupBy는 곧바로 출력하지 말고, Select로 가공 후 출력하면 읽기 쉬운 형태가 된다.
  • Distinct는 참조형 비교 주의. 키로 그룹화 후 첫 항목 선택 패턴이 안전하다.

 

'SQL' 카테고리의 다른 글

SQL 조인 정리 (INNER, OUTER, 다중조인, 인라인 뷰 조인)  (0) 2025.06.12
오라클 - 정규화부터 서브쿼리  (0) 2025.06.11
JOIN 종류  (0) 2025.06.09