Puri๋ SQL์ ๊ฐ๋ ฅํ ์ง๊ณ ํจ์๋ฅผ ํ์
์์ ํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ๋ฌธ์๋ COUNT, SUM, AVG, MAX, MIN๊ณผ GROUP BY, HAVING์ ์ค๋ช
ํฉ๋๋ค.
์ง๊ณ ํจ์ ๊ฐ์
COUNT ๋ ์ฝ๋ ๊ฐ์ ์ธ๊ธฐ Puri.count()
SUM/AVG ํฉ๊ณ์ ํ๊ท ๊ณ์ฐ Puri.sum(), Puri.avg()
MAX/MIN ์ต๋๊ฐ๊ณผ ์ต์๊ฐ ์ฐพ๊ธฐ Puri.max(), Puri.min()
GROUP BY ๊ทธ๋ฃน๋ณ๋ก ์ง๊ณํ๊ธฐ groupBy(), having()
COUNT - ๊ฐ์ ์ธ๊ธฐ
๊ธฐ๋ณธ COUNT
์ ์ฒด ๋ ์ฝ๋ ์
ํน์ ์ปฌ๋ผ COUNT
DISTINCT COUNT
const result = await db
. table ( "employees" )
. select ({
total: Puri . count (),
})
. first ();
console . log ( result . total ); // 150
// ํ์
: { total: number }
Puri.count()๋ COUNT(*)๋ฅผ ์์ฑํฉ๋๋ค. NULL์ ํฌํจํ ๋ชจ๋ ํ์ ์
๋๋ค.
Puri.count("column")์ ํด๋น ์ปฌ๋ผ์ด NULL์ด ์๋ ํ๋ง ์
๋๋ค.
COUNT with GROUP BY
const results = await db
. table ( "employees" )
. select ({
departmentId: "department_id" ,
employeeCount: Puri . count ( "id" ),
})
. groupBy ( "department_id" );
// ๋ถ์๋ณ ์ง์ ์
// [
// { departmentId: 1, employeeCount: 20 },
// { departmentId: 2, employeeCount: 15 },
// ...
// ]
SUM - ํฉ๊ณ
์ซ์ ์ปฌ๋ผ์ ํฉ๊ณ๋ฅผ ๊ณ์ฐํฉ๋๋ค.
const result = await db
. table ( "employees" )
. select ({
totalSalary: Puri . sum ( "salary" ),
})
. first ();
console . log ( result . totalSalary ); // 5000000
// ํ์
: { totalSalary: number }
SUM with GROUP BY
const results = await db
. table ( "employees" )
. select ({
departmentId: "department_id" ,
totalSalary: Puri . sum ( "salary" ),
avgSalary: Puri . avg ( "salary" ),
})
. groupBy ( "department_id" )
. orderBy ( "totalSalary" , "desc" );
// ๋ถ์๋ณ ๊ธ์ฌ ํฉ๊ณ & ํ๊ท
AVG - ํ๊ท
์ซ์ ์ปฌ๋ผ์ ํ๊ท ์ ๊ณ์ฐํฉ๋๋ค.
๊ธฐ๋ณธ AVG
ROUND์ ํจ๊ป
const result = await db
. table ( "employees" )
. select ({
avgSalary: Puri . avg ( "salary" ),
})
. first ();
console . log ( result . avgSalary ); // 65000
// ํ์
: { avgSalary: number }
MAX / MIN - ์ต๋๊ฐ / ์ต์๊ฐ
์ต๋๊ฐ
const result = await db
. table ( "employees" )
. select ({
highestSalary: Puri . max ( "salary" ),
latestHireDate: Puri . max ( "hire_date" ),
})
. first ();
// ๊ฐ์ฅ ๋์ ๊ธ์ฌ, ๊ฐ์ฅ ์ต๊ทผ ์
์ฌ์ผ
์ต์๊ฐ
const result = await db
. table ( "employees" )
. select ({
lowestSalary: Puri . min ( "salary" ),
earliestHireDate: Puri . min ( "hire_date" ),
})
. first ();
// ๊ฐ์ฅ ๋ฎ์ ๊ธ์ฌ, ๊ฐ์ฅ ์ค๋๋ ์
์ฌ์ผ
MAX/MIN with GROUP BY
const results = await db
. table ( "employees" )
. select ({
departmentId: "department_id" ,
minSalary: Puri . min ( "salary" ),
maxSalary: Puri . max ( "salary" ),
avgSalary: Puri . avg ( "salary" ),
})
. groupBy ( "department_id" );
// ๋ถ์๋ณ ์ต์ /์ต๊ณ /ํ๊ท ๊ธ์ฌ
GROUP BY - ๊ทธ๋ฃนํ
๋ฐ์ดํฐ๋ฅผ ํน์ ์ปฌ๋ผ ๊ธฐ์ค์ผ๋ก ๊ทธ๋ฃนํํ์ฌ ์ง๊ณํฉ๋๋ค.
๋จ์ผ ์ปฌ๋ผ GROUP BY
const results = await db
. table ( "employees" )
. select ({
departmentId: "department_id" ,
count: Puri . count ( "id" ),
avgSalary: Puri . avg ( "salary" ),
})
. groupBy ( "department_id" );
// ๋ถ์๋ณ ํต๊ณ
์ฌ๋ฌ ์ปฌ๋ผ GROUP BY
const results = await db
. table ( "employees" )
. select ({
departmentId: "department_id" ,
hireYear: Puri . rawNumber ( "EXTRACT(YEAR FROM hire_date)" ),
count: Puri . count ( "id" ),
})
. groupBy ( "department_id" , "hireYear" )
. orderBy ( "department_id" , "asc" )
. orderBy ( "hireYear" , "asc" );
// ๋ถ์ + ์ฐ๋๋ณ ์ ์
์ง์ ์
GROUP BY ๊ท์น :
SELECT์ ์๋ ์ง๊ณ ํจ์๊ฐ ์๋ ๋ชจ๋ ์ปฌ๋ผ์ GROUP BY์ ์์ด์ผ ํฉ๋๋ค
GROUP BY์ ์๋ ์ปฌ๋ผ์ SELECTํ ์ ์์ต๋๋ค (์ง๊ณ ํจ์ ์ ์ธ)
GROUP BY with JOIN
const results = await db
. table ( "departments" )
. leftJoin ( "employees" , "departments.id" , "employees.department_id" )
. select ({
deptId: "departments.id" ,
deptName: "departments.name" ,
empCount: Puri . count ( "employees.id" ),
avgSalary: Puri . avg ( "employees.salary" ),
})
. groupBy ( "departments.id" , "departments.name" )
. orderBy ( "empCount" , "desc" );
// ๋ถ์๋ณ ์ง์ ์ & ํ๊ท ๊ธ์ฌ
HAVING - ์ง๊ณ ๊ฒฐ๊ณผ ํํฐ๋ง
HAVING์ GROUP BY ํ ์ง๊ณ ๊ฒฐ๊ณผ๋ฅผ ํํฐ๋งํฉ๋๋ค.
๊ธฐ๋ณธ HAVING
const results = await db
. table ( "employees" )
. select ({
departmentId: "department_id" ,
count: Puri . count ( "id" ),
})
. groupBy ( "department_id" )
. having ( "count" , ">=" , 10 );
// ์ง์ 10๋ช
์ด์์ธ ๋ถ์๋ง
WHERE vs HAVING :
WHERE: GROUP BY ์ ์ ํํฐ๋ง (๊ฐ๋ณ ํ ๋์)
HAVING: GROUP BY ํ ์ ํํฐ๋ง (์ง๊ณ ๊ฒฐ๊ณผ ๋์)
HAVING with ์ง๊ณ ํจ์
const results = await db
. table ( "employees" )
. select ({
departmentId: "department_id" ,
avgSalary: Puri . avg ( "salary" ),
count: Puri . count ( "id" ),
})
. groupBy ( "department_id" )
. having ( "avgSalary" , ">" , 70000 )
. having ( "count" , ">=" , 5 );
// ํ๊ท ๊ธ์ฌ 7๋ง ์ด์ & ์ง์ 5๋ช
์ด์์ธ ๋ถ์
WHERE + HAVING ์กฐํฉ
const results = await db
. table ( "employees" )
. select ({
departmentId: "department_id" ,
avgSalary: Puri . avg ( "salary" ),
})
. where ( "hire_date" , ">=" , "2020-01-01" ) // ๊ฐ๋ณ ํ ํํฐ
. groupBy ( "department_id" )
. having ( "avgSalary" , ">" , 65000 ); // ์ง๊ณ ๊ฒฐ๊ณผ ํํฐ
// 2020๋
์ดํ ์
์ฌ์ ์ค, ๋ถ์๋ณ ํ๊ท ๊ธ์ฌ 6.5๋ง ์ด์
๋ณตํฉ ์ง๊ณ ์์
๋ถ์๋ณ ์์ธ ํต๊ณ
const stats = await db
. table ( "departments" )
. leftJoin ( "employees" , "departments.id" , "employees.department_id" )
. select ({
deptId: "departments.id" ,
deptName: "departments.name" ,
// ์ง์ ์
empCount: Puri . count ( "employees.id" ),
// ๊ธ์ฌ ํต๊ณ
minSalary: Puri . min ( "employees.salary" ),
maxSalary: Puri . max ( "employees.salary" ),
avgSalary: Puri . avg ( "employees.salary" ),
totalSalary: Puri . sum ( "employees.salary" ),
// ์
์ฌ์ผ ํต๊ณ
earliestHire: Puri . min ( "employees.hire_date" ),
latestHire: Puri . max ( "employees.hire_date" ),
})
. groupBy ( "departments.id" , "departments.name" )
. having ( "empCount" , ">" , 0 )
. orderBy ( "empCount" , "desc" );
ํ๋ก์ ํธ ์งํ ํํฉ
const projectStats = await db
. table ( "projects" )
. leftJoin ( "projects__employees" , "projects.id" , "projects__employees.project_id" )
. select ({
projectId: "projects.id" ,
projectName: "projects.name" ,
status: "projects.status" ,
memberCount: Puri . count ( "projects__employees.employee_id" ),
})
. groupBy ( "projects.id" , "projects.name" , "projects.status" )
. orderBy ( "status" , "asc" )
. orderBy ( "memberCount" , "desc" );
// ํ๋ก์ ํธ๋ณ ์ฐธ์ฌ์ ์ (์ํ๋ณ ์ ๋ ฌ)
์๋ณ ๋งค์ถ ๋ถ์
const monthlySales = await db
. table ( "orders" )
. select ({
year: Puri . rawNumber ( "EXTRACT(YEAR FROM created_at)" ),
month: Puri . rawNumber ( "EXTRACT(MONTH FROM created_at)" ),
orderCount: Puri . count ( "id" ),
totalAmount: Puri . sum ( "amount" ),
avgAmount: Puri . avg ( "amount" ),
})
. where ( "status" , "completed" )
. groupBy ( "year" , "month" )
. orderBy ( "year" , "desc" )
. orderBy ( "month" , "desc" );
// ์๋ณ ์ฃผ๋ฌธ ํต๊ณ
์กฐ๊ฑด๋ถ ์ง๊ณ
CASE WHEN์ ์ฌ์ฉํ ์กฐ๊ฑด๋ถ ์ง๊ณ์
๋๋ค.
์ํ๋ณ ์นด์ดํธ
const stats = await db
. table ( "projects" )
. select ({
totalProjects: Puri . count ( "id" ),
activeProjects: Puri . rawNumber ( `
COUNT(CASE WHEN status = 'in_progress' THEN 1 END)
` ),
completedProjects: Puri . rawNumber ( `
COUNT(CASE WHEN status = 'completed' THEN 1 END)
` ),
cancelledProjects: Puri . rawNumber ( `
COUNT(CASE WHEN status = 'cancelled' THEN 1 END)
` ),
})
. first ();
// ์ ์ฒด/์งํ์ค/์๋ฃ/์ทจ์ ํ๋ก์ ํธ ์
๊ตฌ๊ฐ๋ณ ์ง๊ณ
const salaryRanges = await db
. table ( "employees" )
. select ({
under50k: Puri . rawNumber ( `
COUNT(CASE WHEN salary < 50000 THEN 1 END)
` ),
range50to70k: Puri . rawNumber ( `
COUNT(CASE WHEN salary BETWEEN 50000 AND 70000 THEN 1 END)
` ),
above70k: Puri . rawNumber ( `
COUNT(CASE WHEN salary > 70000 THEN 1 END)
` ),
})
. first ();
// ๊ธ์ฌ ๊ตฌ๊ฐ๋ณ ์ง์ ์
์ค์ ์์
๋์๋ณด๋ ํต๊ณ
async getDashboardStats () {
// ์ ์ฒด ํต๊ณ
const overall = await this . getPuri ( "r" )
. table ( "employees" )
. select ({
totalEmployees: Puri . count ( "id" ),
avgSalary: Puri . avg ( "salary" ),
maxSalary: Puri . max ( "salary" ),
minSalary: Puri . min ( "salary" ),
})
. first ();
// ๋ถ์๋ณ ํต๊ณ
const byDepartment = await this . getPuri ( "r" )
. table ( "departments" )
. leftJoin ( "employees" , "departments.id" , "employees.department_id" )
. select ({
deptName: "departments.name" ,
empCount: Puri . count ( "employees.id" ),
avgSalary: Puri . avg ( "employees.salary" ),
})
. groupBy ( "departments.id" , "departments.name" )
. orderBy ( "empCount" , "desc" )
. limit ( 10 );
return {
overall ,
byDepartment ,
};
}
์
์ฌ ์ฐ๋๋ณ ํต๊ณ
async getHiringTrends () {
const trends = await this . getPuri ( "r" )
. table ( "employees" )
. select ({
year: Puri . rawNumber ( "EXTRACT(YEAR FROM hire_date)" ),
hireCount: Puri . count ( "id" ),
avgSalary: Puri . avg ( "salary" ),
})
. groupBy ( "year" )
. orderBy ( "year" , "desc" )
. limit ( 5 );
return trends ;
}
TOP 5 ๋ถ์
async getTop5Departments () {
const top5 = await this . getPuri ( "r" )
. table ( "departments" )
. leftJoin ( "employees" , "departments.id" , "employees.department_id" )
. select ({
deptId: "departments.id" ,
deptName: "departments.name" ,
empCount: Puri . count ( "employees.id" ),
totalSalary: Puri . sum ( "employees.salary" ),
avgSalary: Puri . avg ( "employees.salary" ),
})
. groupBy ( "departments.id" , "departments.name" )
. having ( "empCount" , ">" , 0 )
. orderBy ( "totalSalary" , "desc" )
. limit ( 5 );
return top5 ;
}
์ฑ๋ฅ ์ต์ ํ
์ธ๋ฑ์ค ํ์ฉ
-- GROUP BYํ ์ปฌ๋ผ์ ์ธ๋ฑ์ค
CREATE INDEX idx_employees_department_id ON employees(department_id);
CREATE INDEX idx_employees_hire_date ON employees(hire_date);
-- ์ง๊ณํ ์ปฌ๋ผ์ ์ธ๋ฑ์ค (์ ํ์ )
CREATE INDEX idx_employees_salary ON employees(salary);
ํ์ํ ์ง๊ณ๋ง ์ํ
// โ ๋์จ: ๋ถํ์ํ ์ง๊ณ
await db
. table ( "employees" )
. select ({
count: Puri . count ( "id" ),
sum: Puri . sum ( "salary" ),
avg: Puri . avg ( "salary" ),
max: Puri . max ( "salary" ),
min: Puri . min ( "salary" ),
// ... ๋ ๋ง์ ์ง๊ณ
})
. groupBy ( "department_id" );
// โ
์ข์: ํ์ํ ๊ฒ๋ง
await db
. table ( "employees" )
. select ({
departmentId: "department_id" ,
count: Puri . count ( "id" ),
avgSalary: Puri . avg ( "salary" ),
})
. groupBy ( "department_id" );
WHERE๋ก ๋จผ์ ํํฐ๋ง
// โ
์ข์: ์ง๊ณ ์ ๋ถํ์ํ ํ ์ ๊ฑฐ
await db
. table ( "employees" )
. where ( "is_active" , true ) // ๋จผ์ ํํฐ
. where ( "hire_date" , ">=" , "2020-01-01" )
. select ({
departmentId: "department_id" ,
avgSalary: Puri . avg ( "salary" ),
})
. groupBy ( "department_id" );
ํ์
์์ ์ฑ
์ง๊ณ ํจ์์ ๊ฒฐ๊ณผ ํ์
์ด ์๋์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค.
const result = await db
. table ( "employees" )
. select ({
count: Puri . count ( "id" ), // number
avgSalary: Puri . avg ( "salary" ), // number
maxDate: Puri . max ( "hire_date" ), // string (๋ ์ง๋ ๋ฌธ์์ด๋ก ๋ฐํ)
})
. first ();
result . count ; // number
result . avgSalary ; // number
result . maxDate ; // string
๋ค์ ๋จ๊ณ