When the client isn't enough
Some queries — window functions, CTEs, full-text search — are easier in SQL. $queryRaw runs SQL written as a tagged template: every ${value} becomes a bound parameter, so it's safe from SQL injection.
Raw queries and errors
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
const city = "Pokhara";
const rows = await prisma.$queryRaw`
SELECT c.name, count(o.id)::int AS orders,
rank() OVER (ORDER BY count(o.id) DESC)::int AS rank
FROM "Customer" c LEFT JOIN "Order" o ON o."customerId" = c.id
WHERE c.city = ${city}
GROUP BY c.id ORDER BY rank, c.name`;
console.log(rows);
const n = await prisma.$executeRaw`UPDATE "Dish" SET price = price + 5 WHERE veg = ${true}`;
console.log("updated", n);
try {
await prisma.customer.create({ data: { name: "Asha 2", email: "[email protected]", city: "Pokhara" } });
} catch (e) {
if (e.code === "P2002") console.log("Email already used:", e.meta?.target);
else throw e;
}⚠️ Never use $queryRawUnsafe with user input glued into the string — that is exactly SQL injection.