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 |