22 āļž.āļ„. 2568·āļ­āđˆāļēāļ™ 1 āļ™āļēāļ—āļĩ

PostgreSQL generated columns āđ€āļžāļ·āđˆāļ­āđ€āļĢāđˆāļ‡āļ•āļąāļ§āļāļĢāļ­āļ‡āđƒāļ™āļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™

āđ€āļĢāļĩāļĒāļ™āļĢāļđāđ‰āļ§āļīāļ˜āļĩāđƒāļŠāđ‰ PostgreSQL generated columns āđ€āļžāļ·āđˆāļ­āđ€āļĢāđˆāļ‡āļ•āļąāļ§āļāļĢāļ­āļ‡āđāļĨāļ°āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļšāļ™āļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™ āđƒāļŦāđ‰ SQL āļ­āđˆāļēāļ™āļ‡āđˆāļēāļĒāļ‚āļķāđ‰āļ™ āļžāļĢāđ‰āļ­āļĄāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāđāļĨāļ°āļāļēāļĢāļ•āļĢāļ§āļˆāđ€āļŠāđ‡āļāļ­āļĒāđˆāļēāļ‡āļĢāļ§āļ”āđ€āļĢāđ‡āļ§

PostgreSQL generated columns āđ€āļžāļ·āđˆāļ­āđ€āļĢāđˆāļ‡āļ•āļąāļ§āļāļĢāļ­āļ‡āđƒāļ™āļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™

āļ—āļģāđ„āļĄāļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™āļ–āļķāļ‡āļŠāđ‰āļēāđāļĨāļ°āļĒāļļāđˆāļ‡āđ„āļ”āđ‰āđ€āļĢāđ‡āļ§\n\nāļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™āļĄāļąāļāļˆāļ°āđ€āļĢāļīāđˆāļĄāļˆāļēāļāđ€āļĢāļ·āđˆāļ­āļ‡āļ‡āđˆāļēāļĒ āđ†: āļ•āļēāļĢāļēāļ‡ āļŠāļąāļāļ•āļąāļ§āļāļĢāļ­āļ‡ āđāļĨāļ°āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļš â€œāđƒāļŦāļĄāđˆāļŠāļļāļ”āļāđˆāļ­āļ™â€ āđāļ•āđˆāđ€āļĄāļ·āđˆāļ­āļĢāļ°āļšāļšāđƒāļŠāđ‰āļ‡āļēāļ™āļˆāļĢāļīāļ‡ āļ„āļģāļ‚āļ­āļˆāļēāļāļāđˆāļēāļĒāļ•āđˆāļēāļ‡ āđ† āđ€āļĢāļīāđˆāļĄāđ€āļžāļīāđˆāļĄāļ‚āļķāđ‰āļ™ Support āļ•āđ‰āļ­āļ‡āļāļēāļĢāļ„āđ‰āļ™āļŦāļēāļĨāļđāļāļ„āđ‰āļēāļ”āđ‰āļ§āļĒāļŠāļ·āđˆāļ­ āļ­āļĩāđ€āļĄāļĨ āđāļĨāļ°āđ‚āļ—āļĢāļĻāļąāļžāļ—āđŒ āļāđˆāļēāļĒāļ‚āļēāļĒāļ­āļĒāļēāļāđ€āļĢāļĩāļĒāļ‡āļ•āļēāļĄ â€œāļāļīāļˆāļāļĢāļĢāļĄāļĨāđˆāļēāļŠāļļāļ”” āļāđˆāļēāļĒāļāļēāļĢāđ€āļ‡āļīāļ™āļ­āļĒāļēāļāļāļĢāļ­āļ‡ â€œāļĒāļ­āļ”āļ„āđ‰āļēāļ‡āļŠāļģāļĢāļ°â€ āļ„āļģāļ‚āļ­āđāļ•āđˆāļĨāļ°āļ­āļĒāđˆāļēāļ‡āđ€āļžāļīāđˆāļĄāđ€āļ‡āļ·āđˆāļ­āļ™āđ„āļ‚ āļāļēāļĢ join āđāļĨāļ°āļāļēāļĢāļ„āļģāļ™āļ§āļ“āđ€āļĨāđ‡āļ āđ† āļ™āđ‰āļ­āļĒ āđ†\n\nāļĢāļēāļĒāļāļēāļĢāđāļ­āļ”āļĄāļīāļ™āļŠāđˆāļ§āļ™āđƒāļŦāļāđˆāļŠāđ‰āļēāļĨāļ‡āļ”āđ‰āļ§āļĒāđ€āļŦāļ•āļļāļœāļĨāđ€āļ”āļĩāļĒāļ§āļāļąāļ™: āļ—āļļāļāļāļēāļĢāļ„āļĨāļīāļāļˆāļ°āđ€āļ›āļĨāļĩāđˆāļĒāļ™āļ„āļģāļŠāļąāđˆāļ‡ SQL. āļāļēāļĢāļāļĢāļ­āļ‡āđāļĨāļ°āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ­āļēāļˆāļ—āļģāđƒāļŦāđ‰āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļ•āđ‰āļ­āļ‡āļŠāđāļāļ™āđāļ–āļ§āļˆāļģāļ™āļ§āļ™āļĄāļēāļ āđ‚āļ”āļĒāđ€āļ‰āļžāļēāļ°āđ€āļĄāļ·āđˆāļ­āļ„āļģāļŠāļąāđˆāļ‡āļ•āđ‰āļ­āļ‡āļ„āļģāļ™āļ§āļ“āļ„āđˆāļēāļ•āđˆāļ­āđāļ–āļ§āļāđˆāļ­āļ™āļˆāļ°āļ•āļąāļ”āļŠāļīāļ™āđ„āļ”āđ‰āļ§āđˆāļēāđāļ–āļ§āđ„āļŦāļ™āļ•āļĢāļ‡āļ•āļēāļĄāđ€āļ‡āļ·āđˆāļ­āļ™āđ„āļ‚\n\nāļˆāļļāļ”āđ€āļ›āļĨāļĩāđˆāļĒāļ™āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļ„āļ·āļ­āđ€āļĄāļ·āđˆāļ­ WHERE āđāļĨāļ° ORDER BY āļ–āļđāļāđ€āļ•āļīāļĄāļ”āđ‰āļ§āļĒāļ™āļīāļžāļˆāļ™āđŒāđāļ—āļ™āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ•āļĢāļ‡ āđ† āđāļ—āļ™āļ—āļĩāđˆāļˆāļ°āļāļĢāļ­āļ‡āļ”āđ‰āļ§āļĒāļ„āļ­āļĨāļąāļĄāļ™āđŒāļ˜āļĢāļĢāļĄāļ”āļē āļ„āļļāļ“āļ­āļēāļˆāļāļĢāļ­āļ‡āļ”āđ‰āļ§āļĒ lower(email), date_trunc('day', last_seen_at) āļŦāļĢāļ·āļ­ CASE āļ—āļĩāđˆāđāļĄāđ‡āļ›āļŠāļ–āļēāļ™āļ°āļŦāļĨāļēāļĒāļ•āļąāļ§āđ€āļ›āđ‡āļ™āļāļĨāļļāđˆāļĄāđ€āļ”āļĩāļĒāļ§ āļ™āļīāļžāļˆāļ™āđŒāđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āđ„āļĄāđˆāđ€āļžāļĩāļĒāļ‡āđāļ•āđˆāļŠāđ‰āļēāļĨāļ‡ āđāļ•āđˆāļĒāļąāļ‡āļ—āļģāđƒāļŦāđ‰ SQL āļ­āđˆāļēāļ™āļĒāļēāļ āļŦāļēāļĒāļēāļāļ•āđˆāļ­āļāļēāļĢāļ—āļģāļ”āļąāļŠāļ™āļĩ āđāļĨāļ°āđ€āļŠāļĩāđˆāļĒāļ‡āļ•āđˆāļ­āļ„āļ§āļēāļĄāļœāļīāļ”āļžāļĨāļēāļ”\n\nSQL āđāļ­āļ”āļĄāļīāļ™āļ—āļĩāđˆāļĒāļļāđˆāļ‡āļĄāļąāļāļĄāļēāļˆāļēāļāļĢāļđāļ›āđāļšāļšāļ‹āđ‰āļģ āđ† āļšāļēāļ‡āļ­āļĒāđˆāļēāļ‡:\n\n- āļāļĨāđˆāļ­āļ‡āļ„āđ‰āļ™āļŦāļēāļŦāļ™āļķāđˆāļ‡āļ­āļąāļ™āļ—āļĩāđˆāđ€āļŠāđ‡āļāļŦāļĨāļēāļĒāļŸāļīāļĨāļ”āđŒāļ”āđ‰āļ§āļĒāļāļŽāļ•āđˆāļēāļ‡āļāļąāļ™\n- āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āđ‚āļ”āļĒāļ„āđˆāļēāļ—āļĩāđˆāđ„āļ”āđ‰āļˆāļēāļāļāļēāļĢāļ„āļģāļ™āļ§āļ“ (āļŠāļ·āđˆāļ­āđ€āļ•āđ‡āļĄ āļ„āđˆāļēāļ„āļ°āđāļ™āļ™āļ„āļ§āļēāļĄāļŠāļģāļ„āļąāļ āļŦāļĢāļ·āļ­ â€œāđ€āļŦāļ•āļļāļāļēāļĢāļ“āđŒāļĨāđˆāļēāļŠāļļāļ””)\n- āļāļŽāļ˜āļļāļĢāļāļīāļˆāļ—āļĩāđˆāļ„āļąāļ”āļĨāļ­āļāđ„āļ›āļĄāļēāļ‚āđ‰āļēāļĄāļŦāļ™āđ‰āļēāļˆāļ­ (active vs inactive, paid vs overdue)\n- āļāļēāļĢāļ›āļĢāļąāļšāđāļ•āđˆāļ‡āđ€āļĨāđ‡āļ āđ† āļ™āđ‰āļ­āļĒ āđ† (trim, lower, coalesce) āļāļĢāļ°āļˆāļēāļĒāļ­āļĒāļđāđˆāļ—āļļāļāļ—āļĩāđˆ\n- āļ„āđˆāļēāļ„āļģāļ™āļ§āļ“āđ€āļ”āļĩāļĒāļ§āļāļąāļ™āļ–āļđāļāđƒāļŠāđ‰āļ—āļąāđ‰āļ‡āđƒāļ™āļĢāļēāļĒāļāļēāļĢ āļ•āļąāļ§āļāļĢāļ­āļ‡ āđāļĨāļ°āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļš\n\nāļ—āļĩāļĄāļĄāļąāļāļžāļĒāļēāļĒāļēāļĄāļ‹āđˆāļ­āļ™āļ„āļ§āļēāļĄāļĒāļļāđˆāļ‡āđ€āļŦāļĒāļīāļ‡āļ™āļĩāđ‰āđ„āļ§āđ‰āļ—āļĩāđˆāļŠāļąāđ‰āļ™āđāļ­āļ›: āļ•āļąāļ§āļŠāļĢāđ‰āļēāļ‡āļ„āļģāļŠāļąāđˆāļ‡ SQL āđāļšāļšāđ„āļ”āļ™āļēāļĄāļīāļ āļāļēāļĢ join āđāļšāļšāļĄāļĩāđ€āļ‡āļ·āđˆāļ­āļ™āđ„āļ‚ āļŦāļĢāļ·āļ­āļāļēāļĢāļ„āļģāļ™āļ§āļ“āļĨāđˆāļ§āļ‡āļŦāļ™āđ‰āļēāđƒāļ™āđ‚āļ„āđ‰āļ” āļ™āļąāđˆāļ™āļ­āļēāļˆāļŠāđˆāļ§āļĒāđ„āļ”āđ‰ āđāļ•āđˆāļāđ‡āļ—āļģāđƒāļŦāđ‰āļ•āļĢāļĢāļāļ°āļāļĢāļ°āļˆāļēāļĒāļĢāļ°āļŦāļ§āđˆāļēāļ‡ UI āđāļĨāļ°āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨ āļ‹āļķāđˆāļ‡āļ—āļģāđƒāļŦāđ‰āļāļēāļĢāļ”āļĩāļšāļąāļāļ„āļģāļŠāļąāđˆāļ‡āļŠāđ‰āļēāļ—āļģāđ„āļ”āđ‰āļĒāļēāļ\n\nāđ€āļ›āđ‰āļēāļŦāļĄāļēāļĒāļŠāļąāļ”āđ€āļˆāļ™: āļ„āļģāļŠāļąāđˆāļ‡āļ—āļĩāđˆāđ€āļĢāđ‡āļ§āđāļĨāļ°āļ­āđˆāļēāļ™āđ„āļ”āđ‰ āđ€āļĄāļ·āđˆāļ­āļ„āđˆāļēāļ—āļĩāđˆāļ„āļģāļ™āļ§āļ“āļāļĨāļąāļšāļĄāļēāđƒāļŠāđ‰āļšāđˆāļ­āļĒāļšāļ™āļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™ PostgreSQL generated columns āļˆāļ°āđ€āļāđ‡āļšāļāļŽāđ„āļ§āđ‰āđƒāļ™āļ—āļĩāđˆāđ€āļ”āļĩāļĒāļ§āđāļĨāļ°āļĒāļąāļ‡āđƒāļŦāđ‰āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāđ„āļ”āđ‰\n\n## Generated columns āļ­āļ˜āļīāļšāļēāļĒāđāļšāļšāļ‡āđˆāļēāļĒ āđ†\n\nGenerated column āļ„āļ·āļ­āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ›āļāļ•āļīāđƒāļ™āļ•āļēāļĢāļēāļ‡āļ—āļĩāđˆāļ„āđˆāļēāļ‚āļ­āļ‡āļĄāļąāļ™āļ–āļđāļāļ„āļģāļ™āļ§āļ“āļˆāļēāļāļ„āļ­āļĨāļąāļĄāļ™āđŒāļ­āļ·āđˆāļ™ āđ† āļ„āļļāļ“āđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āđ€āļ‚āļĩāļĒāļ™āļ„āđˆāļēāļ™āļąāđ‰āļ™āđ€āļ­āļ‡ PostgreSQL āļˆāļ°āđ€āļ•āļīāļĄāļ„āđˆāļēāđƒāļŦāđ‰āđ‚āļ”āļĒāđƒāļŠāđ‰āļ™āļīāļžāļˆāļ™āđŒāļ—āļĩāđˆāļ„āļļāļ“āļāļģāļŦāļ™āļ”\n\nāđƒāļ™ PostgreSQL generated columns āđ€āļ›āđ‡āļ™āđāļšāļšāđ€āļāđ‡āļšāļˆāļĢāļīāļ‡ (stored). PostgreSQL āļ„āļģāļ™āļ§āļ“āļ„āđˆāļēāļ•āļ­āļ™āđāļ—āļĢāļāļŦāļĢāļ·āļ­āļ­āļąāļ›āđ€āļ”āļ•āđāļ–āļ§āđāļĨāđ‰āļ§āļšāļąāļ™āļ—āļķāļāļĨāļ‡āļ”āļīāļŠāļāđŒāđ€āļŦāļĄāļ·āļ­āļ™āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ—āļąāđˆāļ§āđ„āļ› āļ™āļąāđˆāļ™āļĄāļąāļāļ•āļĢāļ‡āļāļąāļšāļ„āļ§āļēāļĄāļ•āđ‰āļ­āļ‡āļāļēāļĢāļ‚āļ­āļ‡āļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™: āļ­āđˆāļēāļ™āđ€āļĢāđ‡āļ§ āđāļĨāļ°āļŠāļēāļĄāļēāļĢāļ–āļ—āļģāļ”āļąāļŠāļ™āļĩāļ„āđˆāļēāļ—āļĩāđˆāļ„āļģāļ™āļ§āļ“āđ„āļ”āđ‰\n\nāļŠāļīāđˆāļ‡āļ™āļĩāđ‰āļ•āđˆāļēāļ‡āļˆāļēāļāļāļēāļĢāļ„āļģāļ™āļ§āļ“āđ€āļ”āļīāļĄāđƒāļ™āļ—āļļāļ āđ† āļ„āļģāļŠāļąāđˆāļ‡ āļ–āđ‰āļēāļ„āļļāļ“āļĒāļąāļ‡āļ„āļ‡āđ€āļ‚āļĩāļĒāļ™ WHERE lower(email) = lower($1) āļ‹āđ‰āļģ āđ† āļŦāļĢāļ·āļ­āđ€āļĢāļĩāļĒāļ‡āļ”āđ‰āļ§āļĒ last_name || ', ' || first_name āļ„āļļāļ“āļ•āđ‰āļ­āļ‡āļˆāđˆāļēāļĒāļ„āđˆāļēāļāļēāļĢāļ„āļģāļ™āļ§āļ“āļ‹āđ‰āļģ āđ† āđāļĨāļ° SQL āļ‚āļ­āļ‡āļ„āļļāļ“āļˆāļ°āļĢāļāļ‚āļķāđ‰āļ™ Generated column āļĒāđ‰āļēāļĒāļāļēāļĢāļ„āļģāļ™āļ§āļ“āļ‹āđ‰āļģ āđ† āļ™āļąāđ‰āļ™āđ„āļ›āđ„āļ§āđ‰āđƒāļ™āļāļēāļĢāļ­āļ­āļāđāļšāļšāļ•āļēāļĢāļēāļ‡ āļ—āļģāđƒāļŦāđ‰āļ„āļģāļŠāļąāđˆāļ‡āđ€āļĢāļĩāļĒāļšāļ‡āđˆāļēāļĒāđāļĨāļ°āļœāļĨāļĨāļąāļžāļ˜āđŒāļ„āļ‡āļ—āļĩāđˆāļ—āļąāđˆāļ§āļĢāļ°āļšāļš\n\nāđ€āļĄāļ·āđˆāļ­āļ‚āđ‰āļ­āļĄāļđāļĨāļ•āđ‰āļ™āļ—āļēāļ‡āđ€āļ›āļĨāļĩāđˆāļĒāļ™ PostgreSQL āļˆāļ°āļ­āļąāļ›āđ€āļ”āļ•āļ„āđˆāļēāļ—āļĩāđˆāļ„āļģāļ™āļ§āļ“āđƒāļŦāđ‰āđ‚āļ”āļĒāļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļīāļŠāļģāļŦāļĢāļąāļšāđāļ–āļ§āļ™āļąāđ‰āļ™ āđāļ­āļ›āļ‚āļ­āļ‡āļ„āļļāļ“āđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āļˆāļģāļ§āđˆāļēāļ•āđ‰āļ­āļ‡āļ‹āļīāļ‡āļāđŒāļ„āđˆāļē\n\nāđāļšāļšāļˆāļģāļĨāļ­āļ‡āļ„āļ§āļēāļĄāļ„āļīāļ”āļ—āļĩāđˆāļĄāļĩāļ›āļĢāļ°āđ‚āļĒāļŠāļ™āđŒ:\n\n- āļ™āļīāļĒāļēāļĄāļŠāļđāļ•āļĢāļ„āļĢāļąāđ‰āļ‡āđ€āļ”āļĩāļĒāļ§\n- PostgreSQL āļ„āļģāļ™āļ§āļ“āļ•āļ­āļ™āđ€āļ‚āļĩāļĒāļ™ (writes)\n- āļ„āļģāļŠāļąāđˆāļ‡āļ­āđˆāļēāļ™āđ€āļŦāļĄāļ·āļ­āļ™āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ›āļāļ•āļī\n- āđ€āļžāļĢāļēāļ°āđ€āļ›āđ‡āļ™āđāļšāļšāđ€āļāđ‡āļšāļˆāļĢāļīāļ‡ āļ„āļļāļ“āļŠāļēāļĄāļēāļĢāļ–āļ—āļģāļ”āļąāļŠāļ™āļĩāđ„āļ”āđ‰\n\nāļ–āđ‰āļēāļ„āļļāļ“āđ€āļ›āļĨāļĩāđˆāļĒāļ™āļŠāļđāļ•āļĢāļ āļēāļĒāļŦāļĨāļąāļ‡ āļ„āļļāļ“āļ•āđ‰āļ­āļ‡āđ€āļ›āļĨāļĩāđˆāļĒāļ™āļŠāļ„āļĩāļĄāļē āļ§āļēāļ‡āđāļœāļ™āđ€āļŦāļĄāļ·āļ­āļ™āļĄāļīāđ€āļāļĢāļŠāļąāļ™āļ›āļāļ•āļī āđ€āļžāļĢāļēāļ°āđāļ–āļ§āļ—āļĩāđˆāļĄāļĩāļ­āļĒāļđāđˆāļˆāļ°āļ•āđ‰āļ­āļ‡āļ­āļąāļ›āđ€āļ”āļ•āđƒāļŦāđ‰āļ•āļĢāļ‡āļāļąāļšāļ™āļīāļžāļˆāļ™āđŒāđƒāļŦāļĄāđˆ\n\n## āļāļĢāļ“āļĩāļ—āļĩāđˆāđ€āļŦāļĄāļēāļ°āļŠāļģāļŦāļĢāļąāļšāļŸāļīāļĨāļ”āđŒāļ—āļĩāđˆāļ„āļģāļ™āļ§āļ“āđƒāļ™āļāļēāļĢāļāļĢāļ­āļ‡āđāļĨāļ°āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļš\n\nGenerated columns āđ€āļ”āđˆāļ™āđ€āļĄāļ·āđˆāļ­āļ„āđˆāļēāļ™āļąāđ‰āļ™āļ–āļđāļāļ­āļ™āļļāļĄāļēāļ™āļˆāļēāļāļ„āļ­āļĨāļąāļĄāļ™āđŒāļ­āļ·āđˆāļ™ āđ† āđ€āļŠāļĄāļ­ āđāļĨāļ°āļ„āļļāļ“āļāļĢāļ­āļ‡āļŦāļĢāļ·āļ­āđ€āļĢāļĩāļĒāļ‡āļšāļ™āļ„āđˆāļēāļ™āļąāđ‰āļ™āļšāđˆāļ­āļĒ āđ† āļžāļ§āļāļĄāļąāļ™āđ„āļĄāđˆāļ„āđˆāļ­āļĒāļĄāļĩāļ›āļĢāļ°āđ‚āļĒāļŠāļ™āđŒāļāļąāļšāļĢāļēāļĒāļ‡āļēāļ™āđāļšāļšāļ„āļĢāļąāđ‰āļ‡āđ€āļ”āļĩāļĒāļ§\n\n### āļŸāļīāļĨāļ”āđŒāļ„āđ‰āļ™āļŦāļēāļ—āļĩāđˆāļœāļđāđ‰āđƒāļŠāđ‰āļĄāļąāļāđƒāļŠāđ‰āļˆāļĢāļīāļ‡\n\nāļāļēāļĢāļ„āđ‰āļ™āļŦāļēāđƒāļ™āđāļ­āļ”āļĄāļīāļ™āđ„āļĄāđˆāļ„āđˆāļ­āļĒāđ€āļ›āđ‡āļ™ â€œāļāļēāļĢāļ„āđ‰āļ™āļŦāļēāļĨāđ‰āļ§āļ™ āđ†â€ āļ„āļ™āļĄāļąāļāļ„āļēāļ”āļŦāļ§āļąāļ‡āļ§āđˆāļēāļāļĨāđˆāļ­āļ‡āļ„āđ‰āļ™āļŦāļēāļˆāļ°āļˆāļąāļ”āļāļēāļĢāļ‚āđ‰āļ­āļ„āļ§āļēāļĄāļĢāļ āđ† āļ•āļąāļ§āļžāļīāļĄāļžāđŒāđƒāļŦāļāđˆāđ€āļĨāđ‡āļāđ„āļĄāđˆāļŠāļĄāđˆāļģāđ€āļŠāļĄāļ­ āđāļĨāļ°āļŠāđˆāļ­āļ‡āļ§āđˆāļēāļ‡āļ—āļĩāđˆāđ€āļāļīāļ™āļĄāļēāđ„āļ”āđ‰ āļ–āđ‰āļēāļ„āļļāļ“āđ€āļāđ‡āļš search key āļ—āļĩāđˆāļ–āļđāļāļ›āļĢāļąāļšāđƒāļŦāđ‰āļ­āļĒāļđāđˆāđƒāļ™āļĢāļđāļ›āđāļšāļšāļ›āļāļ•āļīāđ„āļ§āđ‰ āļ„āļģāļŠāļąāđˆāļ‡ WHERE āļāđ‡āļˆāļ°āļ­āđˆāļēāļ™āļ‡āđˆāļēāļĒāđāļĨāļ°āļžāļĪāļ•āļīāļāļĢāļĢāļĄāļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļāļąāļ™āļ—āļąāđˆāļ§āļŦāļ™āđ‰āļēāļˆāļ­\n\nāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āļ—āļĩāđˆāđ€āļŦāļĄāļēāļ°āļŠāļĄāļĢāļ§āļĄāļ–āļķāļ‡āļŠāļ·āđˆāļ­āđ€āļ•āđ‡āļĄāļĢāļ§āļĄāļāļąāļ™āļ—āļĩāđˆāļ—āļģāđƒāļŦāđ‰āđ€āļ›āđ‡āļ™āļ•āļąāļ§āļžāļīāļĄāļžāđŒāđ€āļĨāđ‡āļāđāļĨāļ°āļ•āļąāļ”āļŠāđˆāļ­āļ‡āļ§āđˆāļēāļ‡ āļ‚āđ‰āļ­āļ„āļ§āļēāļĄāļ—āļĩāđˆāļĨāļšāļŠāđˆāļ­āļ‡āļ§āđˆāļēāļ‡āļ‹āđ‰āļģ āļŦāļĢāļ·āļ­āļ›āđ‰āļēāļĒāļŠāļ–āļēāļ™āļ°āļ—āļĩāđˆāđ„āļ”āđ‰āļˆāļēāļāļŦāļĨāļēāļĒāļŸāļīāļĨāļ”āđŒ\n\nāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡: āđāļ—āļ™āļ—āļĩāđˆāļˆāļ°āđ€āļ‚āļĩāļĒāļ™ lower(trim(first_name || ' ' || last_name)) āļ‹āđ‰āļģ āđ† āđƒāļŦāđ‰āļŠāļĢāđ‰āļēāļ‡ full_name_key āļ„āļĢāļąāđ‰āļ‡āđ€āļ”āļĩāļĒāļ§āđāļĨāđ‰āļ§āļāļĢāļ­āļ‡āļ”āđ‰āļ§āļĒāļ„āđˆāļēāļ™āļąāđ‰āļ™\n\n### āļ„āļĩāļĒāđŒāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ—āļĩāđˆāļ•āļĢāļ‡āļāļąāļšāļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļ‚āļ­āļ‡āļ„āļ™\n\nāļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ„āļ·āļ­āļ—āļĩāđˆāļ—āļĩāđˆāļŸāļīāļĨāļ”āđŒāļ„āļģāļ™āļ§āļ“āļĄāļąāļāļ„āļ·āļ™āļœāļĨāđ€āļĢāđ‡āļ§āļ—āļĩāđˆāļŠāļļāļ” āđ€āļžāļĢāļēāļ°āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļ­āļēāļˆāļšāļąāļ‡āļ„āļąāļšāđƒāļŦāđ‰ PostgreSQL āļ›āļĢāļ°āđ€āļĄāļīāļ™āļ™āļīāļžāļˆāļ™āđŒāļŠāļģāļŦāļĢāļąāļšāļŦāļĨāļēāļĒāđāļ–āļ§\n\nāļ„āļĩāļĒāđŒāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāđ„āļ”āđ‰āđāļāđˆ āļĢāļ°āļ”āļąāļšāđ€āļŠāļīāļ‡āļ•āļąāļ§āđ€āļĨāļ‚ (āđ€āļŠāđˆāļ™ āđāļœāļ™āļšāļĢāļīāļāļēāļĢāđāļĄāđ‡āļ›āđ€āļ›āđ‡āļ™ 1, 2, 3), timestamp āļ‚āļ­āļ‡ â€œāļāļīāļˆāļāļĢāļĢāļĄāļĨāđˆāļēāļŠāļļāļ”” āđ€āļ”āļĩāļĒāļ§ (āđ€āļŠāđˆāļ™ max āļ‚āļ­āļ‡āļŠāļ­āļ‡ timestamp), āļŦāļĢāļ·āļ­āđ‚āļ„āđ‰āļ”āļ—āļĩāđˆāđ€āļ•āļīāļĄāļĻāļđāļ™āļĒāđŒāđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āđ€āļĢāļĩāļĒāļ‡āļ–āļđāļāļ•āđ‰āļ­āļ‡āđāļšāļšāļ‚āđ‰āļ­āļ„āļ§āļēāļĄ\n\nāđ€āļĄāļ·āđˆāļ­āļ„āļĩāļĒāđŒāđ€āļĢāļĩāļĒāļ‡āđ€āļ›āđ‡āļ™āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ˜āļĢāļĢāļĄāļ”āļēāļ—āļĩāđˆāļ—āļģāļ”āļąāļŠāļ™āļĩ ORDER BY āļˆāļ°āļ–āļđāļāļĨāļ‡āļ„āđˆāļēāđƒāļŠāđ‰āļˆāđˆāļēāļĒāļĄāļēāļāļ‚āļķāđ‰āļ™\n\n### āļ˜āļ‡āļ—āļĩāđˆāļ­āļ™āļļāļĄāļēāļ™āđ„āļ”āđ‰āļŠāļģāļŦāļĢāļąāļšāļ•āļąāļ§āļāļĢāļ­āļ‡āļ”āđˆāļ§āļ™\n\nāļœāļđāđ‰āđƒāļŠāđ‰āđāļ­āļ”āļĄāļīāļ™āļŠāļ­āļšāļāļĨāđˆāļ­āļ‡āļ•āļīāđŠāļāđ€āļŠāđˆāļ™ â€œāļ„āđ‰āļēāļ‡āļŠāļģāļĢāļ°â€ āļŦāļĢāļ·āļ­ â€œāļĄāļđāļĨāļ„āđˆāļēāļŠāļđāļ‡â€ āļžāļ§āļāļ™āļĩāđ‰āļ—āļģāļ‡āļēāļ™āđ„āļ”āđ‰āļ”āļĩāđ€āļ›āđ‡āļ™ generated columns āđ€āļĄāļ·āđˆāļ­āļ•āļĢāļĢāļāļ°āļ„āļ‡āļ—āļĩāđˆāđāļĨāļ°āļ­āđ‰āļēāļ‡āļ­āļīāļ‡āđ€āļ‰āļžāļēāļ°āļ‚āđ‰āļ­āļĄāļđāļĨāđƒāļ™āđāļ–āļ§āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™\n\nāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡: āļ–āđ‰āļēāļĢāļēāļĒāļāļēāļĢāļĨāļđāļāļ„āđ‰āļēāļ•āđ‰āļ­āļ‡āļāļēāļĢ â€œāļĄāļĩāļ‚āđ‰āļ­āļ„āļ§āļēāļĄāļĒāļąāļ‡āđ„āļĄāđˆāļ­āđˆāļēāļ™â€ āđāļĨāļ° â€œāļ„āđ‰āļēāļ‡āļŠāļģāļĢāļ°â€ āđƒāļŦāđ‰āļŠāļĢāđ‰āļēāļ‡ has_unread boolean (āļˆāļēāļ unread_count > 0) āđāļĨāļ° is_overdue (āļˆāļēāļ due_date < now() āđāļĨāļ° paid_at is null) āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āļ•āļąāļ§āļāļĢāļ­āļ‡āđƒāļ™ UI āļāļĨāļēāļĒāđ€āļ›āđ‡āļ™āđ€āļ‡āļ·āđˆāļ­āļ™āđ„āļ‚āļ‡āđˆāļēāļĒ āđ†\n\n## āļāļēāļĢāđ€āļĨāļ·āļ­āļāļĢāļ°āļŦāļ§āđˆāļēāļ‡ generated columns, āļ”āļąāļŠāļ™āļĩ, āđāļĨāļ°āļ•āļąāļ§āđ€āļĨāļ·āļ­āļāļ­āļ·āđˆāļ™ āđ†\n\nāļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™āļ•āđ‰āļ­āļ‡āļāļēāļĢāļŠāļēāļĄāļ­āļĒāđˆāļēāļ‡: āļāļēāļĢāļāļĢāļ­āļ‡āđ€āļĢāđ‡āļ§ āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āđ€āļĢāđ‡āļ§ āđāļĨāļ° SQL āļ—āļĩāđˆāļ„āļļāļ“āļĒāļąāļ‡āļ­āđˆāļēāļ™āļ­āļ­āļāđ„āļ”āđ‰āđ€āļĄāļ·āđˆāļ­āļœāđˆāļēāļ™āđ„āļ›āļŦāļĨāļēāļĒāđ€āļ”āļ·āļ­āļ™ āļāļēāļĢāļ•āļąāļ”āļŠāļīāļ™āđƒāļˆāļˆāļĢāļīāļ‡āļ„āļ·āļ­āļāļēāļĢāđ€āļĨāļ·āļ­āļāļ§āđˆāļēāļāļēāļĢāļ„āļģāļ™āļ§āļ“āļˆāļ°āļ­āļĒāļđāđˆāļ—āļĩāđˆāđ„āļŦāļ™: āđƒāļ™āļ•āļēāļĢāļēāļ‡ āđƒāļ™āļ”āļąāļŠāļ™āļĩ āđƒāļ™ view āļŦāļĢāļ·āļ­āđƒāļ™āđ‚āļ„āđ‰āļ”āđāļ­āļ›\n\nGenerated columns āđ€āļŦāļĄāļēāļ°āđ€āļĄāļ·āđˆāļ­āļ„āļļāļ“āļ•āđ‰āļ­āļ‡āļāļēāļĢāđƒāļŦāđ‰āļ„āđˆāļēāļ—āļģāļ•āļąāļ§āđ€āļŦāļĄāļ·āļ­āļ™āļ„āļ­āļĨāļąāļĄāļ™āđŒāļˆāļĢāļīāļ‡: āļ­āđ‰āļēāļ‡āļ­āļīāļ‡āļ‡āđˆāļēāļĒ āđāļŠāļ”āļ‡āđƒāļ™ SELECT āđ„āļ”āđ‰ āđāļĨāļ°āđ„āļĄāđˆāļĨāļ·āļĄāđ€āļ§āļĨāļēāđ€āļžāļīāđˆāļĄāļ•āļąāļ§āļāļĢāļ­āļ‡āđƒāļŦāļĄāđˆ āļžāļ§āļāļĄāļąāļ™āļĒāļąāļ‡āđ€āļ‚āđ‰āļēāļāļąāļ™āļ”āļĩāļāļąāļšāļ”āļąāļŠāļ™āļĩāđāļšāļšāļ›āļāļ•āļī\n\nExpression indexes āđ€āļžāļīāđˆāļĄāđ€āļĢāđ‡āļ§āļāļ§āđˆāļēāđ€āļžāļĢāļēāļ°āđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āđ€āļ›āļĨāļĩāđˆāļĒāļ™āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āļ•āļēāļĢāļēāļ‡ āļ–āđ‰āļēāļ„āļļāļ“āđ€āļ™āđ‰āļ™āļ„āļ§āļēāļĄāđ€āļĢāđ‡āļ§āđāļĨāļ°āđ„āļĄāđˆāļāļąāļ‡āļ§āļĨāđ€āļĢāļ·āđˆāļ­āļ‡ SQL āļ—āļĩāđˆāļ”āļđāļĢāļ āļāļēāļĢāļ—āļģāļ”āļąāļŠāļ™āļĩāđāļšāļšāļ™āļīāļžāļˆāļ™āđŒāļĄāļąāļāļžāļ­āđ€āļžāļĩāļĒāļ‡ āļ‚āđ‰āļ­āļ”āđ‰āļ­āļĒāļ„āļ·āļ­āđ€āļĢāļ·āđˆāļ­āļ‡āļ„āļ§āļēāļĄāļ­āđˆāļēāļ™āđ„āļ”āđ‰ āđāļĨāļ°āļ„āļļāļ“āļžāļķāđˆāļ‡āļžāļē planner āđƒāļŦāđ‰āļˆāļąāļšāļ„āļđāđˆāļāļąāļšāļ™āļīāļžāļˆāļ™āđŒāļ—āļĩāđˆāļ•āļĢāļ‡āđ€āļ›āđŠāļ°\n\nViews āļŠāđˆāļ§āļĒāđ€āļĄāļ·āđˆāļ­āļ„āļļāļ“āļ•āđ‰āļ­āļ‡āļāļēāļĢ â€œāļĢāļđāļ›āļĢāđˆāļēāļ‡â€ āļ‚āļ­āļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāđƒāļŠāđ‰āļĢāđˆāļ§āļĄāļāļąāļ™ āđ‚āļ”āļĒāđ€āļ‰āļžāļēāļ°āļ–āđ‰āļēāļĢāļēāļĒāļāļēāļĢāđāļ­āļ”āļĄāļīāļ™ join āļŦāļĨāļēāļĒāļ•āļēāļĢāļēāļ‡ āđāļ•āđˆ view āļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™āļ­āļēāļˆāļ‹āđˆāļ­āļ™āļ‡āļēāļ™āļ—āļĩāđˆāļŦāļ™āļąāļāđāļĨāļ°āđ€āļžāļīāđˆāļĄāļˆāļļāļ”āļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļ”āļĩāļšāļąāļ\n\nTriggers āļŠāļēāļĄāļēāļĢāļ–āļ—āļģāđƒāļŦāđ‰āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ›āļāļ•āļīāļ‹āļīāļ‡āļāđŒāđ„āļ”āđ‰ āđāļ•āđˆāđ€āļžāļīāđˆāļĄāļŠāļīāđ‰āļ™āļŠāđˆāļ§āļ™āļ—āļĩāđˆāđ€āļ„āļĨāļ·āđˆāļ­āļ™āđ„āļŦāļ§ āļžāļ§āļāļĄāļąāļ™āļ­āļēāļˆāļ—āļģāđƒāļŦāđ‰āļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ•āđāļšāļšāļāļĨāļļāđˆāļĄāļŠāđ‰āļēāļĨāļ‡āđāļĨāļ°āļĄāļąāļāļ–āļđāļāļĄāļ­āļ‡āļ‚āđ‰āļēāļĄāđ€āļĄāļ·āđˆāļ­āļ”āļĩāļšāļąāļ\n\nāļšāļēāļ‡āļ„āļĢāļąāđ‰āļ‡āļ—āļēāļ‡āđ€āļĨāļ·āļ­āļāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”āļ„āļ·āļ­āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ˜āļĢāļĢāļĄāļ”āļēāļ—āļĩāđˆāđ€āļ•āļīāļĄāđ‚āļ”āļĒāđāļ­āļ› āļŦāļēāļāļœāļđāđ‰āđƒāļŠāđ‰āļŠāļēāļĄāļēāļĢāļ–āđāļāđ‰āđ„āļ‚āļ„āđˆāļēāđ„āļ”āđ‰ āļŦāļĢāļ·āļ­āļŠāļđāļ•āļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āļšāđˆāļ­āļĒāļ•āļēāļĄāļ™āđ‚āļĒāļšāļēāļĒāļ˜āļļāļĢāļāļīāļˆ (āđ„āļĄāđˆāđƒāļŠāđˆāđāļ„āđˆāļ‚āđ‰āļ­āļĄāļđāļĨāđāļ–āļ§) āļāļēāļĢāđ€āļāđ‡āļšāđ„āļ§āđ‰āļ­āļĒāđˆāļēāļ‡āļŠāļąāļ”āđ€āļˆāļ™āļˆāļ°āļŠāļąāļ”āđ€āļˆāļ™āļāļ§āđˆāļē\n\nāļ§āļīāļ˜āļĩāļ•āļąāļ”āļŠāļīāļ™āđƒāļˆāļ­āļĒāđˆāļēāļ‡āļĢāļ§āļ”āđ€āļĢāđ‡āļ§:\n\n- āļ•āđ‰āļ­āļ‡āļāļēāļĢāļ„āļģāļŠāļąāđˆāļ‡āļ­āđˆāļēāļ™āļ‡āđˆāļēāļĒāđāļĨāļ°āļŠāļđāļ•āļĢāļ„āļ‡āļ—āļĩāđˆāļ—āļĩāđˆāļ­āļīāļ‡āđāļ„āđˆāļ‚āđ‰āļ­āļĄāļđāļĨāđāļ–āļ§? āđƒāļŠāđ‰ generated column.\n- āļ•āđ‰āļ­āļ‡āļāļēāļĢāļ„āļ§āļēāļĄāđ€āļĢāđ‡āļ§āļŠāļģāļŦāļĢāļąāļšāļ•āļąāļ§āļāļĢāļ­āļ‡āđ€āļ‰āļžāļēāļ°āđāļĨāļ°āđ„āļĄāđˆāļāļąāļ‡āļ§āļ™āļ™āļąāļāđ€āļĢāļ·āđˆāļ­āļ‡ SQL āļĢāļ? āđƒāļŠāđ‰ expression index.\n- āļ•āđ‰āļ­āļ‡āļāļēāļĢāļĢāļđāļ›āļĢāđˆāļēāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāđāļšāļš join āļ—āļĩāđˆāđƒāļŠāđ‰āļ‹āđ‰āļģāļŦāļĨāļēāļĒāļ—āļĩāđˆ? āļžāļīāļˆāļēāļĢāļ“āļē view.\n- āļ•āđ‰āļ­āļ‡āļāļēāļĢāļ•āļĢāļĢāļāļ°āļ‚āđ‰āļēāļĄāļ•āļēāļĢāļēāļ‡āļŦāļĢāļ·āļ­āļœāļĨāļ‚āđ‰āļēāļ‡āđ€āļ„āļĩāļĒāļ‡? āđƒāļŦāđ‰āđ‚āļŸāļāļąāļŠāļ—āļĩāđˆāđ‚āļĨāļˆāļīāļāđƒāļ™āđāļ­āļ›āļāđˆāļ­āļ™ āđƒāļŠāđ‰ trigger āđ€āļ›āđ‡āļ™āļ—āļēāļ‡āđ€āļĨāļ·āļ­āļāļŠāļļāļ”āļ—āđ‰āļēāļĒ.\n\n## āļ—āļĩāļĨāļ°āļ‚āļąāđ‰āļ™āļ•āļ­āļ™: āđ€āļžāļīāđˆāļĄ generated column āđāļĨāļ°āđƒāļŠāđ‰āđƒāļ™āļ„āļģāļŠāļąāđˆāļ‡\n\nāđ€āļĢāļīāđˆāļĄāļˆāļēāļāļ„āļģāļŠāļąāđˆāļ‡āļĢāļēāļĒāļāļēāļĢāđāļ­āļ”āļĄāļīāļ™āļŠāđ‰āļēāļ—āļĩāđˆāļ„āļļāļ“āļĢāļđāđ‰āļŠāļķāļāļŠāđ‰āļēāđƒāļ™ UI āđ€āļ‚āļĩāļĒāļ™āļĨāļ‡āļ§āđˆāļēāļŦāļ™āđ‰āļēāļˆāļ­āđƒāļŠāđ‰āļ•āļąāļ§āļāļĢāļ­āļ‡āđāļĨāļ°āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ­āļ°āđ„āļĢāļšāđ‰āļēāļ‡ āļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āļ„āļģāļŠāļąāđˆāļ‡āđ€āļ”āļĩāļĒāļ§āļ—āļĩāđˆāđ€āļŦāđ‡āļ™āļœāļĨāļāđˆāļ­āļ™\n\nāđ€āļĨāļ·āļ­āļāļŸāļīāļĨāļ”āđŒāļ—āļĩāđˆāļ„āļģāļ™āļ§āļ“āļ‹āļķāđˆāļ‡āļĨāļ”āļ‡āļēāļ™āļ‹āđ‰āļģ āđāļĨāļ°āļ•āļąāđ‰āļ‡āļŠāļ·āđˆāļ­āļ•āļēāļĄāļĄāļēāļ•āļĢāļāļēāļ™ snake_case āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āļ„āļ™āļ­āļ·āđˆāļ™āļ„āļēāļ”āđ€āļ”āļēāđ„āļ”āđ‰āļ§āđˆāļēāļĄāļąāļ™āđ€āļāđ‡āļšāļ­āļ°āđ„āļĢāđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āļ­āđˆāļēāļ™āļ™āļīāļžāļˆāļ™āđŒāđƒāļŦāļĄāđˆ\n\n### 1) āđ€āļžāļīāđˆāļĄ generated column (STORED)\n\nsql\nALTER TABLE customers\nADD COLUMN full_name_key text\nGENERATED ALWAYS AS (\n lower(concat_ws(' ', last_name, first_name))\n) STORED;\n\n\nāļ•āļĢāļ§āļˆāļœāļĨāļāļąāļšāļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļĢāļīāļ‡āļāđˆāļ­āļ™āđ€āļžāļīāđˆāļĄāļ”āļąāļŠāļ™āļĩ:\n\nsql\nSELECT id, first_name, last_name, full_name_key\nFROM customers\nORDER BY id DESC\nLIMIT 5;\n\n\nāļ–āđ‰āļēāļœāļĨāļĨāļąāļžāļ˜āđŒāļœāļīāļ” āđƒāļŦāđ‰āđāļāđ‰āļ™āļīāļžāļˆāļ™āđŒāļ•āļ­āļ™āļ™āļĩāđ‰ STORED āļŦāļĄāļēāļĒāļ„āļ§āļēāļĄāļ§āđˆāļē PostgreSQL āļˆāļ°āđ€āļāđ‡āļšāļ„āđˆāļēāļ—āļĩāđˆāļ­āļąāļ›āđ€āļ”āļ•āļ•āļ­āļ™āđāļ—āļĢāļāđāļĨāļ°āļ­āļąāļ›āđ€āļ”āļ•āđāļ–āļ§\n\n### 2) āđ€āļžāļīāđˆāļĄāļ”āļąāļŠāļ™āļĩāļ—āļĩāđˆāļ•āļĢāļ‡āļāļąāļšāļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™\n\nāļ–āđ‰āļēāļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™āļāļĢāļ­āļ‡āļ•āļēāļĄ status āđāļĨāļ°āđ€āļĢāļĩāļĒāļ‡āļ•āļēāļĄāļŠāļ·āđˆāļ­ āđƒāļŦāđ‰āļŠāļĢāđ‰āļēāļ‡āļ”āļąāļŠāļ™āļĩāđāļšāļšāļ™āļĩāđ‰:\n\nsql\nCREATE INDEX customers_status_full_name_key_idx\nON customers (status, full_name_key);\n\n\n### 3) āļ­āļąāļ›āđ€āļ”āļ•āļ„āļģāļŠāļąāđˆāļ‡āđāļ­āļ”āļĄāļīāļ™āđƒāļŦāđ‰āđƒāļŠāđ‰āļ„āļ­āļĨāļąāļĄāļ™āđŒāđƒāļŦāļĄāđˆ\n\nāļāđˆāļ­āļ™āļŦāļ™āđ‰āļēāļ™āļĩāđ‰āļ„āļļāļ“āļ­āļēāļˆāļĄāļĩ ORDER BY āļ—āļĩāđˆāļĒāļļāđˆāļ‡ āļŦāļĨāļąāļ‡āļˆāļēāļāļ™āļĩāđ‰āļĄāļąāļ™āļŠāļąāļ”āđ€āļˆāļ™:\n\nsql\nSELECT id, status, first_name, last_name\nFROM customers\nWHERE status = 'active'\nORDER BY full_name_key ASC\nLIMIT 50 OFFSET 0;\n\n\nāđƒāļŠāđ‰ generated columns āļāļąāļšāļŠāđˆāļ§āļ™āļ—āļĩāđˆāļ„āļ™āļāļĢāļ­āļ‡āđāļĨāļ°āđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ—āļļāļāļ§āļąāļ™ āđ„āļĄāđˆāđƒāļŠāđˆāļŦāļ™āđ‰āļēāļˆāļ­āļŦāļēāļĒāļēāļ\n\n## āļĢāļđāļ›āđāļšāļšāļāļēāļĢāļ—āļģāļ”āļąāļŠāļ™āļĩāļ—āļĩāđˆāļ•āļĢāļ‡āļāļąāļšāļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™āļˆāļĢāļīāļ‡\n\nāļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™āļĄāļąāļāļ—āļģāļžāļĪāļ•āļīāļāļĢāļĢāļĄāļ‹āđ‰āļģ āđ†: āļāļĢāļ­āļ‡āļ”āđ‰āļ§āļĒāđ„āļĄāđˆāļāļĩāđˆāļŸāļīāļĨāļ”āđŒ āđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ”āđ‰āļ§āļĒāļ„āļ­āļĨāļąāļĄāļ™āđŒāļŦāļ™āļķāđˆāļ‡ āđāļĨāđ‰āļ§āđāļšāđˆāļ‡āļŦāļ™āđ‰āļē āļāļēāļĢāļ•āļąāđ‰āļ‡āļ„āđˆāļēāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”āđ„āļĄāđˆāđƒāļŠāđˆ “āļ—āļģāļ”āļąāļŠāļ™āļĩāļ—āļļāļāļ­āļĒāđˆāļēāļ‡â€ āđāļ•āđˆāđ€āļ›āđ‡āļ™ â€œāļ—āļģāļ”āļąāļŠāļ™āļĩāļĢāļđāļ›āđāļšāļšāļ‚āļ­āļ‡āļ„āļģāļŠāļąāđˆāļ‡āļ—āļĩāđˆāđƒāļŠāđ‰āļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ””\n\nāļāļŽāļ›āļāļīāļšāļąāļ•āļī: āđƒāļŠāđˆāļ„āļ­āļĨāļąāļĄāļ™āđŒāļāļĢāļ­āļ‡āļ—āļĩāđˆāđƒāļŠāđ‰āļšāđˆāļ­āļĒāđ„āļ§āđ‰āļ”āđ‰āļēāļ™āļŦāļ™āđ‰āļē āđāļĨāļ°āļ„āļ­āļĨāļąāļĄāļ™āđŒāđ€āļĢāļĩāļĒāļ‡āļ—āļĩāđˆāđƒāļŠāđ‰āļšāđˆāļ­āļĒāđ„āļ§āđ‰āļ—āđ‰āļēāļĒ āļ–āđ‰āļēāļ„āļļāļ“āđƒāļŠāđ‰ multi-tenant workspace_id āļĄāļąāļāļˆāļ°āļ­āļĒāļđāđˆāļ”āđ‰āļēāļ™āļŦāļ™āđ‰āļē āđ€āļŠāđˆāļ™ (workspace_id, status, created_at)\n\nāļāļēāļĢāļ„āđ‰āļ™āļŦāļēāļ”āđ‰āļ§āļĒāļ‚āđ‰āļ­āļ„āļ§āļēāļĄāđ€āļ›āđ‡āļ™āļ›āļąāļāļŦāļēāļ­āļĩāļāđ€āļĢāļ·āđˆāļ­āļ‡ āļāļĨāđˆāļ­āļ‡āļ„āđ‰āļ™āļŦāļēāļŦāļĨāļēāļĒāļ—āļĩāđˆāļāļĨāļēāļĒāđ€āļ›āđ‡āļ™ ILIKE '%term%' āļ‹āļķāđˆāļ‡āļĒāļēāļāļˆāļ°āđ€āļĢāđˆāļ‡āļ”āđ‰āļ§āļĒ btree āļ˜āļĢāļĢāļĄāļ”āļē āđāļ™āļ§āļ—āļēāļ‡āļ—āļĩāđˆāļŠāđˆāļ§āļĒāđ„āļ”āđ‰āļ„āļ·āļ­āđ€āļāđ‡āļšāļ„āļ­āļĨāļąāļĄāļ™āđŒāļŠāđˆāļ§āļĒāļ„āđ‰āļ™āļŦāļēāļ—āļĩāđˆāļ–āļđāļāļ—āļģāđƒāļŦāđ‰āđ€āļ›āđ‡āļ™āļĄāļēāļ•āļĢāļāļēāļ™āđāļ—āļ™āļāļēāļĢāļ„āđ‰āļ™āļŦāļēāđƒāļ™āļ‚āđ‰āļ­āļ„āļ§āļēāļĄāļ”āļīāļš (āļ•āļąāļ§āļžāļīāļĄāļžāđŒāđ€āļĨāđ‡āļ āļ•āļąāļ”āļŠāđˆāļ­āļ‡āļ§āđˆāļēāļ‡ āļšāļēāļ‡āļ—āļĩāļĢāļ§āļĄāļāļąāļ™) āļ–āđ‰āļē UI āļ‚āļ­āļ‡āļ„āļļāļ“āļĒāļ­āļĄāļĢāļąāļšāļāļēāļĢāļ„āđ‰āļ™āļŦāļēāđāļšāļšāļžāļĒāļēāļ‡āļ„āđŒāļ‚āļķāđ‰āļ™āļ•āđ‰āļ™ (term%) āļ”āļąāļŠāļ™āļĩ btree āļšāļ™āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ—āļĩāđˆāļ›āļĢāļąāļšāđāļĨāđ‰āļ§āļˆāļ°āļŠāđˆāļ§āļĒāđ„āļ”āđ‰ āļ–āđ‰āļēāļ•āđ‰āļ­āļ‡āđ€āļ›āđ‡āļ™ contains (%term%) āđƒāļŦāđ‰āļžāļīāļˆāļēāļĢāļ“āļēāļ›āļĢāļąāļšāļžāļĪāļ•āļīāļāļĢāļĢāļĄ UI āļŦāļĢāļ·āļ­āļˆāļģāļāļąāļ”āļŠāļļāļ”āļ‚āđ‰āļ­āļĄāļđāļĨāđƒāļ™āļāļēāļĢāļ„āđ‰āļ™āļŦāļē\n\nāļ•āļĢāļ§āļˆ selectivity āļāđˆāļ­āļ™āđ€āļžāļīāđˆāļĄāļ”āļąāļŠāļ™āļĩ āļ–āđ‰āļēāļ„āđˆāļē 95% āļ‚āļ­āļ‡āđāļ–āļ§āļĄāļĩāļ„āđˆāļēāđ€āļ”āļĩāļĒāļ§āļāļąāļ™ (āđ€āļŠāđˆāļ™ status = 'active') āļāļēāļĢāļ—āļģāļ”āļąāļŠāļ™āļĩāļ„āļ­āļĨāļąāļĄāļ™āđŒāļ™āļąāđ‰āļ™āļ­āļĒāđˆāļēāļ‡āđ€āļ”āļĩāļĒāļ§āļŠāđˆāļ§āļĒāļ™āđ‰āļ­āļĒ āđƒāļŦāđ‰āļˆāļąāļšāļ„āļđāđˆāļāļąāļšāļ„āļ­āļĨāļąāļĄāļ™āđŒāļ—āļĩāđˆāļĄāļĩāļāļēāļĢāļāļĢāļ°āļˆāļēāļĒāļĄāļēāļāļāļ§āđˆāļē āļŦāļĢāļ·āļ­āđƒāļŠāđ‰ partial index āļŠāļģāļŦāļĢāļąāļšāļāļĢāļ“āļĩāļŠāđˆāļ§āļ™āļ™āđ‰āļ­āļĒ\n\n## āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āļŠāļĄāļˆāļĢāļīāļ‡: āļŦāļ™āđ‰āļēāđāļ­āļ”āļĄāļīāļ™āļĨāļđāļāļ„āđ‰āļēāļ—āļĩāđˆāļĒāļąāļ‡āđ€āļĢāđ‡āļ§\n\nāļĨāļ­āļ‡āļ™āļķāļāļ āļēāļžāļŦāļ™āđ‰āļēāļĨāļđāļāļ„āđ‰āļēāļ—āļąāđˆāļ§āđ„āļ›: āļāļĨāđˆāļ­āļ‡āļ„āđ‰āļ™āļŦāļē āļ•āļąāļ§āļāļĢāļ­āļ‡āđ„āļĄāđˆāļāļĩāđˆāļ­āļĒāđˆāļēāļ‡ (inactive, āļŠāđˆāļ§āļ‡āļĒāļ­āļ”āļ„āļ‡āđ€āļŦāļĨāļ·āļ­) āđāļĨāļ°āļ„āļ­āļĨāļąāļĄāļ™āđŒāđ€āļĢāļĩāļĒāļ‡ â€œLast seen” āļ—āļĩāđˆāđ€āļĢāļĩāļĒāļ‡āđ„āļ”āđ‰ āđ€āļĄāļ·āđˆāļ­āđ€āļ§āļĨāļēāļœāđˆāļēāļ™āđ„āļ› SQL āļˆāļ°āđ€āļ•āđ‡āļĄāđ„āļ›āļ”āđ‰āļ§āļĒ LOWER(), TRIM(), COALESCE(), āļ„āļģāļ™āļ§āļ“āļ§āļąāļ™āļ—āļĩāđˆ āđāļĨāļ° CASE āļ‹āđ‰āļģ āđ†\n\nāļ§āļīāļ˜āļĩāļŦāļ™āļķāđˆāļ‡āļ—āļĩāđˆāļ—āļģāđƒāļŦāđ‰āļĄāļąāļ™āđ€āļĢāđ‡āļ§āđāļĨāļ°āļ­āđˆāļēāļ™āļ‡āđˆāļēāļĒāļ„āļ·āļ­āļĒāđ‰āļēāļĒāļ™āļīāļžāļˆāļ™āđŒāļ—āļĩāđˆāļ‹āđ‰āļģāđ„āļ›āđ€āļ›āđ‡āļ™ generated columns\n\n### āļ•āļēāļĢāļēāļ‡āđāļĨāļ° generated columns\n\nāļŠāļĄāļĄāļ•āļīāļ§āđˆāļēāļ•āļēāļĢāļēāļ‡ customers āļĄāļĩ name, email, last_seen, āđāļĨāļ° balance āđƒāļŦāđ‰āđ€āļžāļīāđˆāļĄāļŸāļīāļĨāļ”āđŒāļ„āļģāļ™āļ§āļ“āļŠāļēāļĄāļ•āļąāļ§:\n\n- search_key: āļ‚āđ‰āļ­āļ„āļ§āļēāļĄāļ›āļāļ•āļīāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ„āđ‰āļ™āļŦāļēāđāļšāļšāļ‡āđˆāļēāļĒ\n- is_inactive: boolean āļŠāļģāļŦāļĢāļąāļšāļāļĢāļ­āļ‡āđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āđ€āļ‚āļĩāļĒāļ™āļ•āļĢāļĢāļāļ°āļ§āļąāļ™āļ—āļĩāđˆāļ‹āđ‰āļģ\n- balance_bucket: āļ›āđ‰āļēāļĒāļŠāļģāļŦāļĢāļąāļšāđāļšāđˆāļ‡āļāļĨāļļāđˆāļĄāļĒāļ­āļ”āļ‡āđˆāļēāļĒ āđ†\n\nsql\nALTER TABLE customers\n ADD COLUMN search_key text\n GENERATED ALWAYS AS (\n lower(trim(coalesce(name, ''))) || ' ' || lower(trim(coalesce(email, '')))\n ) STORED,\n ADD COLUMN is_inactive boolean\n GENERATED ALWAYS AS (\n last_seen IS NULL OR last_seen < (now() - interval '90 days')\n ) STORED,\n ADD COLUMN balance_bucket text\n GENERATED ALWAYS AS (\n CASE\n WHEN balance < 0 THEN 'negative'\n WHEN balance < 100 THEN '0-99'\n WHEN balance < 500 THEN '100-499'\n ELSE '500+'\n END\n ) STORED;\n\n\nāļ•āļ­āļ™āļ™āļĩāđ‰āļ„āļģāļŠāļąāđˆāļ‡āļŠāļģāļŦāļĢāļąāļšāđāļ­āļ”āļĄāļīāļ™āļ­āđˆāļēāļ™āđ€āļŦāļĄāļ·āļ­āļ™ UI\n\n### āļ•āļąāļ§āļāļĢāļ­āļ‡ + āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļ—āļĩāđˆāļ­āđˆāļēāļ™āļ‡āđˆāļēāļĒ\n\n“āļĨāļđāļāļ„āđ‰āļēāļ—āļĩāđˆāđ„āļĄāđˆ active āđ€āļĢāļĩāļĒāļ‡āļ•āļēāļĄāļāļīāļˆāļāļĢāļĢāļĄāļĨāđˆāļēāļŠāļļāļ”” āļˆāļ°āļāļĨāļēāļĒāđ€āļ›āđ‡āļ™:\n\nsql\nSELECT id, name, email, last_seen, balance\nFROM customers\nWHERE is_inactive = true\nORDER BY last_seen DESC NULLS LAST\nLIMIT 50;\n\n\nāđāļĨāļ°āļāļēāļĢāļ„āđ‰āļ™āļŦāļēāđ€āļšāļ·āđ‰āļ­āļ‡āļ•āđ‰āļ™āļˆāļ°āđ€āļ›āđ‡āļ™:\n\nsql\nSELECT id, name, email, last_seen, balance\nFROM customers\nWHERE search_key LIKE '%' || lower(trim($1)) || '%'\nORDER BY last_seen DESC NULLS LAST\nLIMIT 50;\n\n\nāļœāļĨāļĨāļąāļžāļ˜āđŒāļˆāļĢāļīāļ‡āļ„āļ·āļ­āļ„āļ§āļēāļĄāļŠāļĄāđˆāļģāđ€āļŠāļĄāļ­ āļŸāļīāļĨāļ”āđŒāđ€āļ”āļĩāļĒāļ§āļāļąāļ™āļ‚āļąāļšāđ€āļ„āļĨāļ·āđˆāļ­āļ™āļŦāļĨāļēāļĒāļŦāļ™āđ‰āļēāļˆāļ­āđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āđ€āļ‚āļĩāļĒāļ™āļ•āļĢāļĢāļāļ°āļ‹āđ‰āļģ:\n\n- āļāļĨāđˆāļ­āļ‡āļ„āđ‰āļ™āļŦāļēāļŦāļ™āđ‰āļēāļĢāļēāļĒāļāļēāļĢāļĨāļđāļāļ„āđ‰āļēāđƒāļŠāđ‰ search_key\n- āđāļ—āđ‡āļš â€œāļĨāļđāļāļ„āđ‰āļēāļ—āļĩāđˆāđ„āļĄāđˆ active” āđƒāļŠāđ‰ is_inactive\n- āļŠāļīāļ›āļ•āļąāļ§āļāļĢāļ­āļ‡āļĒāļ­āļ”āđƒāļŠāđ‰ balance_bucket\n\n## āļ„āļ§āļēāļĄāļœāļīāļ”āļžāļĨāļēāļ”āđāļĨāļ°āļāļąāļšāļ”āļąāļāļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒ\n\nGenerated columns āļ”āļđāđ€āļŦāļĄāļ·āļ­āļ™āļ„āļģāļ•āļ­āļšāļ‡āđˆāļēāļĒ: āđƒāļŠāđˆāļāļēāļĢāļ„āļģāļ™āļ§āļ“āđ„āļ§āđ‰āđƒāļ™āļ•āļēāļĢāļēāļ‡āđāļĨāļ°āļ„āļģāļŠāļąāđˆāļ‡āļˆāļ°āļŠāļ°āļ­āļēāļ”āļ‚āļķāđ‰āļ™ āđāļ•āđˆāļĄāļąāļ™āļˆāļ°āļŠāđˆāļ§āļĒāļāđ‡āļ•āđˆāļ­āđ€āļĄāļ·āđˆāļ­āļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļāļąāļšāļĢāļđāļ›āđāļšāļšāļāļēāļĢāļāļĢāļ­āļ‡āđāļĨāļ°āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡ āđāļĨāļ°āđ€āļĄāļ·āđˆāļ­āļ„āļļāļ“āđ€āļžāļīāđˆāļĄāļ”āļąāļŠāļ™āļĩāļ—āļĩāđˆāļ–āļđāļāļ•āđ‰āļ­āļ‡\n\nāļ„āļ§āļēāļĄāļœāļīāļ”āļžāļĨāļēāļ”āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒ:\n\n- āļ„āļīāļ”āļ§āđˆāļēāļĄāļąāļ™āļˆāļ°āđ€āļĢāđ‡āļ§āļ‚āļķāđ‰āļ™āđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āļ—āļģāļ”āļąāļŠāļ™āļĩ āļ„āđˆāļēāļ—āļĩāđˆāļ„āļģāļ™āļ§āļ“āļĒāļąāļ‡āļ•āđ‰āļ­āļ‡āļāļēāļĢāļ”āļąāļŠāļ™āļĩāđ€āļžāļ·āđˆāļ­āļāļĢāļ­āļ‡āļŦāļĢāļ·āļ­āđ€āļĢāļĩāļĒāļ‡āļ—āļĩāđˆāļ‚āļ™āļēāļ”āđƒāļŦāļāđˆ\n- āļ­āļąāļ”āļ•āļĢāļĢāļāļ°āļĄāļēāļāđ€āļāļīāļ™āđ„āļ›āđƒāļ™āļŸāļīāļĨāļ”āđŒāđ€āļ”āļĩāļĒāļ§ āļ–āđ‰āļēāļ„āļ­āļĨāļąāļĄāļ™āđŒāļ—āļĩāđˆāļŠāļĢāđ‰āļēāļ‡āļ‚āļķāđ‰āļ™āļāļĨāļēāļĒāđ€āļ›āđ‡āļ™āđ‚āļ›āļĢāđāļāļĢāļĄāļĒāđˆāļ­āļĄ āđ† āļœāļđāđ‰āļ„āļ™āļˆāļ°āđ„āļĄāđˆāđ„āļ§āđ‰āļ§āļēāļ‡āđƒāļˆ āđ€āļāđ‡āļšāđƒāļŦāđ‰āļŠāļąāđ‰āļ™āđāļĨāļ°āļ•āļąāđ‰āļ‡āļŠāļ·āđˆāļ­āļŠāļąāļ”āđ€āļˆāļ™\n- āđƒāļŠāđ‰āļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļ—āļĩāđˆāđ„āļĄāđˆ immutable PostgreSQL āļāļģāļŦāļ™āļ”āđƒāļŦāđ‰āļ™āļīāļžāļˆāļ™āđŒāļŠāļģāļŦāļĢāļąāļš stored generated column āļ•āđ‰āļ­āļ‡āđ€āļ›āđ‡āļ™ immutable āļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļ­āļĒāđˆāļēāļ‡ now() āđāļĨāļ° random() āļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ”āļ›āļąāļāļŦāļēāđāļĨāļ°āļĄāļąāļāđ„āļĄāđˆāļ–āļđāļāļ­āļ™āļļāļāļēāļ•\n- āļĄāļ­āļ‡āļ‚āđ‰āļēāļĄāļ„āđˆāļēāđƒāļŠāđ‰āļˆāđˆāļēāļĒāđƒāļ™āļāļēāļĢāđ€āļ‚āļĩāļĒāļ™ āđāļ—āļĢāļāđāļĨāļ°āļ­āļąāļ›āđ€āļ”āļ•āļ•āđ‰āļ­āļ‡āļĢāļąāļāļĐāļēāļ„āđˆāļēāļ—āļĩāđˆāļ„āļģāļ™āļ§āļ“āđ„āļ§āđ‰ āļāļēāļĢāļ­āđˆāļēāļ™āđ€āļĢāđ‡āļ§āļ‚āļķāđ‰āļ™āđ„āļĄāđˆāļ„āļļāđ‰āļĄāļ„āđˆāļēāļ–āđ‰āļēāļāļēāļĢāļ™āļģāđ€āļ‚āđ‰āļēāļ‚āđ‰āļ­āļĄāļđāļĨāļŦāļĢāļ·āļ­āļāļēāļĢāļ‹āļīāļ‡āļāđŒāļŠāđ‰āļēāļˆāļ™āđ€āļāļīāļ™āđ„āļ›\n- āļŠāļĢāđ‰āļēāļ‡āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ—āļĩāđˆāļ‹āđ‰āļģāđ€āļāļ·āļ­āļšāđ€āļŦāļĄāļ·āļ­āļ™āļāļąāļ™ āļĄāļēāļāļāļ§āđˆāļēāļ—āļĩāđˆāļˆāļ°āļĄāļēāļ•āļĢāļāļēāļ™āļŦāļ™āļķāđˆāļ‡āļŦāļĢāļ·āļ­āļŠāļ­āļ‡āļĢāļđāļ›āđāļšāļš (āđ€āļŠāđˆāļ™ key āļ›āļāļ•āļīāđ€āļ”āļĩāļĒāļ§)\n\nāļ–āđ‰āļēāļĢāļēāļĒāļāļēāļĢāđāļ­āļ”āļĄāļīāļ™āļ‚āļ­āļ‡āļ„āļļāļ“āļ•āđ‰āļ­āļ‡āļāļēāļĢāļāļēāļĢāļ„āđ‰āļ™āļŦāļēāđāļšāļš contains (ILIKE '%ann%') generated column āđ€āļžāļĩāļĒāļ‡āļ­āļĒāđˆāļēāļ‡āđ€āļ”āļĩāļĒāļ§āļ„āļ‡āđ„āļĄāđˆāđ€āļžāļĩāļĒāļ‡āļžāļ­ āļ„āļļāļ“āļ­āļēāļˆāļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰āđāļ™āļ§āļ—āļēāļ‡āļāļēāļĢāļ„āđ‰āļ™āļŦāļēāļ­āļ·āđˆāļ™ āđāļ•āđˆāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļāļĢāļ­āļ‡āđāļĨāļ°āđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ›āļĢāļ°āļˆāļģāļ§āļąāļ™āļ—āļĩāđˆāđƒāļŠāđ‰āđ€āļ›āđ‡āļ™āļ›āļĢāļ°āļˆāļģ generated columns āļžāļĢāđ‰āļ­āļĄāļ”āļąāļŠāļ™āļĩāļ—āļĩāđˆāļ–āļđāļāļ•āđ‰āļ­āļ‡āļĄāļąāļāļ—āļģāđƒāļŦāđ‰āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļ„āļēāļ”āđ€āļ”āļēāđ„āļ”āđ‰āļĄāļēāļāļ‚āļķāđ‰āļ™\n\n## āđ€āļŠāđ‡āļ„āļĨāļīāļŠāļ•āđŒāļāđˆāļ­āļ™āļ›āļĨāđˆāļ­āļĒāļ‚āļķāđ‰āļ™āđ‚āļ›āļĢāļ”āļąāļāļŠāļąāļ™\n\nāļāđˆāļ­āļ™āļˆāļ°āļ™āļģāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āđ„āļ›āđƒāļŠāđ‰āļāļąāļšāđāļ­āļ”āļĄāļīāļ™ āļĨāļ­āļ‡āļĒāļ·āļ™āļĒāļąāļ™āļ§āđˆāļēāļ„āđˆāļēāļ—āļĩāđˆāļ„āļģāļ™āļ§āļ“ āļ„āļģāļŠāļąāđˆāļ‡ āđāļĨāļ°āļ”āļąāļŠāļ™āļĩāļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļāļąāļ™\n\n- āļŠāļđāļ•āļĢāļ„āļ‡āļ—āļĩāđˆāđāļĨāļ°āļ­āļ˜āļīāļšāļēāļĒāđƒāļ™āļ›āļĢāļ°āđ‚āļĒāļ„āđ€āļ”āļĩāļĒāļ§āđ„āļ”āđ‰\n- āļ„āļģāļŠāļąāđˆāļ‡āđƒāļŠāđ‰ generated column āļˆāļĢāļīāļ‡āđƒāļ™ WHERE āđāļĨāļ°/āļŦāļĢāļ·āļ­ ORDER BY\n- āļ”āļąāļŠāļ™āļĩāļ•āļĢāļ‡āļāļąāļšāļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™āļˆāļĢāļīāļ‡ āđ„āļĄāđˆāđƒāļŠāđˆāļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ„āļĢāļąāđ‰āļ‡āđ€āļ”āļĩāļĒāļ§\n- āđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļšāļœāļĨāļĨāļąāļžāļ˜āđŒāļāļąāļšāļ•āļĢāļĢāļāļ°āđ€āļ”āļīāļĄāđƒāļ™āļāļĢāļ“āļĩāļ‚āļ­āļšāđ€āļ‚āļ• (NULL, āļŠāļ•āļĢāļīāļ‡āļ§āđˆāļēāļ‡, āļŠāđˆāļ­āļ‡āļ§āđˆāļēāļ‡āļ›āļĢāļ°āļŦāļĨāļēāļ”, āļ•āļąāļ§āļžāļīāļĄāļžāđŒāļœāļŠāļĄ)\n- āļ—āļ”āļŠāļ­āļšāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļāļēāļĢāđ€āļ‚āļĩāļĒāļ™āļ–āđ‰āļēāļ•āļēāļĢāļēāļ‡āļĄāļĩāļ‡āļēāļ™āđ€āļ‚āļĩāļĒāļ™āļĄāļēāļ (imports, background updates, integrations)\n\n## āļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ•āđˆāļ­āđ„āļ›: āļ™āļģāđ„āļ›āđƒāļŠāđ‰āļāļąāļšāļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™āļ‚āļ­āļ‡āļ„āļļāļ“\n\nāđ€āļĨāļ·āļ­āļāļˆāļļāļ”āđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āđ€āļĨāđ‡āļ āđ† āļ—āļĩāđˆāļĄāļĩāļœāļĨāļāļĢāļ°āļ—āļšāļŠāļđāļ‡: 2–3 āļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™āļ—āļĩāđˆāļ„āļ™āđ€āļ›āļīāļ”āļ—āļļāļāļ§āļąāļ™ (orders, customers, tickets). āļˆāļ”āļ§āđˆāļēāļˆāļļāļ”āđ„āļŦāļ™āļĢāļđāđ‰āļŠāļķāļāļŠāđ‰āļē (āļ•āļąāļ§āļāļĢāļ­āļ‡āļ•āļēāļĄāļŠāđˆāļ§āļ‡āļ§āļąāļ™āļ—āļĩāđˆ, āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļ•āļēāļĄ â€œāļāļīāļˆāļāļĢāļĢāļĄāļĨāđˆāļēāļŠāļļāļ””, āļāļēāļĢāļ„āđ‰āļ™āļŦāļēāļŠāļ·āđˆāļ­āļĢāļ§āļĄ, āļāļēāļĢāļāļĢāļ­āļ‡āļ•āļēāļĄāļ›āđ‰āļēāļĒāļŠāļ–āļēāļ™āļ°) āļˆāļēāļāļ™āļąāđ‰āļ™āļĄāļēāļ•āļĢāļāļēāļ™āļŸāļīāļĨāļ”āđŒāļ—āļĩāđˆāļ„āļģāļ™āļ§āļ“āļŠāļąāđ‰āļ™ āđ† āļ—āļĩāđˆāļ™āļģāļāļĨāļąāļšāļĄāļēāđƒāļŠāđ‰āļ‚āđ‰āļēāļĄāļŦāļ™āđ‰āļēāļˆāļ­āđ„āļ”āđ‰\n\nāđāļœāļ™āļāļēāļĢāđ„āļĨāđˆāļ›āļĢāļąāļšāļ—āļĩāđˆāļ§āļąāļ”āļœāļĨāđ„āļ”āđ‰āđāļĨāļ°āļĒāđ‰āļ­āļ™āļāļĨāļąāļšāđ„āļ”āđ‰āļ‡āđˆāļēāļĒ:\n\n- āđ€āļžāļīāđˆāļĄ generated column(s) āđ‚āļ”āļĒāđƒāļŠāđ‰āļŠāļ·āđˆāļ­āļ•āļĢāļ‡āđ„āļ›āļ•āļĢāļ‡āļĄāļē\n- āļĢāļąāļ™āļĢāļ°āļšāļšāđ€āļāđˆāļēāđāļĨāļ°āđƒāļŦāļĄāđˆāļ‚āļ™āļēāļ™āļāļąāļ™āļŠāļąāđ‰āļ™ āđ† āļ–āđ‰āļēāļˆāļ°āļ—āļ”āđāļ—āļ™āļ•āļĢāļĢāļāļ°āđ€āļ”āļīāļĄ\n- āđ€āļžāļīāđˆāļĄāļ”āļąāļŠāļ™āļĩāļ—āļĩāđˆāļ•āļĢāļ‡āļāļąāļšāļ•āļąāļ§āļāļĢāļ­āļ‡āļŦāļĢāļ·āļ­āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļŦāļĨāļąāļ\n- āđ€āļ›āļĨāļĩāđˆāļĒāļ™āļ„āļģāļŠāļąāđˆāļ‡āļŦāļ™āđ‰āļēāļˆāļ­āđƒāļŦāđ‰āđƒāļŠāđ‰āļ„āļ­āļĨāļąāļĄāļ™āđŒāđƒāļŦāļĄāđˆ\n- āļ§āļąāļ”āļāđˆāļ­āļ™āđāļĨāļ°āļŦāļĨāļąāļ‡ (āđ€āļ§āļĨāļē query āđāļĨāļ°āđāļ–āļ§āļ—āļĩāđˆāļŠāđāļāļ™) āđāļĨāđ‰āļ§āļĨāļšāļ§āļīāļ˜āļĩāđāļāđ‰āđ€āļ”āļīāļĄāļ­āļ­āļ\n\nāļ–āđ‰āļēāļ„āļļāļ“āļŠāļĢāđ‰āļēāļ‡āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­āđāļ­āļ”āļĄāļīāļ™āļ āļēāļĒāđƒāļ™āļ”āđ‰āļ§āļĒ AppMaster (appmaster.io) āļŸāļīāļĨāļ”āđŒāļ„āļģāļ™āļ§āļ“āđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āđ€āļ‚āđ‰āļēāļāļąāļšāđ‚āļĄāđ€āļ”āļĨāļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāđāļŠāļĢāđŒāđ„āļ”āđ‰āļ”āļĩ: āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļ–āļ·āļ­āļāļŽāđ„āļ§āđ‰ āđāļĨāļ° UI āļ‚āļ­āļ‡āļ„āļļāļ“āļŠāļēāļĄāļēāļĢāļ–āļŠāļĩāđ‰āđ„āļ›āļ—āļĩāđˆāļŠāļ·āđˆāļ­āļŸāļīāļĨāļ”āđŒāļ•āļĢāļ‡ āđ† āđāļ—āļ™āļāļēāļĢāđ€āļ‚āļĩāļĒāļ™āļ™āļīāļžāļˆāļ™āđŒāļ‹āđ‰āļģāļ‚āđ‰āļēāļĄāļŦāļ™āđ‰āļēāļˆāļ­

āļ„āļģāļ–āļēāļĄāļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒ

When should I use a PostgreSQL generated column for an admin screen?

Generated columns help when you keep repeating the same expression in WHERE or ORDER BY, like normalizing names, mapping statuses, or building a sorting key. They’re especially useful for admin lists that are opened all day and need predictable filtering and sorting.

What’s the difference between a stored generated column and an expression index?

A stored generated column is computed on insert or update and saved like a normal column, so reads can be fast and indexable. An expression index stores the result in the index without adding a new table column, but your queries still need to use the exact expression for the planner to match it.

Will a generated column automatically make my query faster?

No, not by itself. A generated column mainly makes the query simpler and makes indexing a computed value straightforward, but you still need an index that matches your common filters and sorts if you want real speedups at scale.

What are the best generated columns to add for admin search and sorting?

Usually it’s a field you filter or sort on constantly: a normalized search key, a “full name” sort key, a derived boolean like is_overdue, or a ranking number that matches how people expect results to sort. Pick one value that removes repeated work from many queries, not a one-off calculation.

How do I choose the right index for an admin list that filters and sorts?

Start with the most common filter columns, then put the main sort key last, like (workspace_id, status, full_name_key) if that matches the screen. This lets PostgreSQL filter quickly and then return rows already ordered without extra work.

Can generated columns fix slow contains search like ILIKE '%term%'?

Not very. A generated column can normalize text so behavior is consistent, but ILIKE '%term%' still tends to be slow with basic btree indexes on large tables. If performance matters, prefer prefix-style search where you can, reduce the searched dataset with other filters, or adjust the UI behavior for big tables.

Can I create a generated column that depends on now() for “inactive” flags?

Stored generated columns have to be based on immutable expressions, so functions like now() typically aren’t allowed and would also be conceptually wrong because the value would go stale. For time-based flags like “inactive for 90 days,” consider a normal column maintained by a job, or compute it at query time if it’s not heavily used.

What happens if I need to change the formula of a generated column later?

Yes, but plan it like a real migration. Changing the expression means updating the schema and recomputing values for existing rows, which can take time and add write load, so do it in a controlled deployment window if the table is large.

Do generated columns add overhead to inserts and updates?

Yes. The database has to compute and store the value on every insert and update, so heavy write workloads (imports, sync jobs) can slow down if you add too many generated fields or complex expressions. Keep expressions short, add only what you use, and measure write performance on busy tables.

What’s the safest way to roll out generated columns to speed up an existing admin screen?

Add a generated column, validate a few real rows, then add the index that matches the screen’s main filter and sort. Update the admin query to use the new column directly, and compare query time and rows scanned before and after to confirm the change helped.

āļ‡āđˆāļēāļĒāļ•āđˆāļ­āļāļēāļĢāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™
āļŠāļĢāđ‰āļēāļ‡āļšāļēāļ‡āļŠāļīāđˆāļ‡āļ—āļĩāđˆ āļ™āđˆāļēāļ—āļķāđˆāļ‡

āļ—āļ”āļĨāļ­āļ‡āļāļąāļš AppMaster āļ”āđ‰āļ§āļĒāđāļœāļ™āļŸāļĢāļĩ
āđ€āļĄāļ·āđˆāļ­āļ„āļļāļ“āļžāļĢāđ‰āļ­āļĄ āļ„āļļāļ“āļŠāļēāļĄāļēāļĢāļ–āđ€āļĨāļ·āļ­āļāļāļēāļĢāļŠāļĄāļąāļ„āļĢāļ—āļĩāđˆāđ€āļŦāļĄāļēāļ°āļŠāļĄāđ„āļ”āđ‰

āđ€āļĢāļīāđˆāļĄ
PostgreSQL generated columns āđ€āļžāļ·āđˆāļ­āđ€āļĢāđˆāļ‡āļ•āļąāļ§āļāļĢāļ­āļ‡āđƒāļ™āļŦāļ™āđ‰āļēāļˆāļ­āđāļ­āļ”āļĄāļīāļ™ | AppMaster