PostgreSQL generated columns āđāļāļ·āđāļāđāļĢāđāļāļāļąāļ§āļāļĢāļāļāđāļāļŦāļāđāļēāļāļāđāļāļāļĄāļīāļ
āđāļĢāļĩāļĒāļāļĢāļđāđāļ§āļīāļāļĩāđāļāđ PostgreSQL generated columns āđāļāļ·āđāļāđāļĢāđāļāļāļąāļ§āļāļĢāļāļāđāļĨāļ°āļāļēāļĢāđāļĢāļĩāļĒāļāļĨāļģāļāļąāļāļāļāļŦāļāđāļēāļāļāđāļāļāļĄāļīāļ āđāļŦāđ SQL āļāđāļēāļāļāđāļēāļĒāļāļķāđāļ āļāļĢāđāļāļĄāļāļąāļ§āļāļĒāđāļēāļāļāļāļīāļāļąāļāļīāđāļĨāļ°āļāļēāļĢāļāļĢāļ§āļāđāļāđāļāļāļĒāđāļēāļāļĢāļ§āļāđāļĢāđāļ§

āļāļģāđāļĄāļŦāļāđāļēāļāļāđāļāļāļĄāļīāļāļāļķāļāļāđāļēāđāļĨāļ°āļĒāļļāđāļāđāļāđāđāļĢāđāļ§\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 āļāļāļāļāļļāļāļŠāļēāļĄāļēāļĢāļāļāļĩāđāđāļāļāļĩāđāļāļ·āđāļāļāļīāļĨāļāđāļāļĢāļ āđ āđāļāļāļāļēāļĢāđāļāļĩāļĒāļāļāļīāļāļāļāđāļāđāļģāļāđāļēāļĄāļŦāļāđāļēāļāļ
āļāļģāļāļēāļĄāļāļĩāđāļāļāļāđāļāļĒ
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.


