{"id":112596,"date":"2026-11-02T12:00:00","date_gmt":"2026-11-02T12:00:00","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=112596"},"modified":"2026-10-22T13:31:02","modified_gmt":"2026-10-22T13:31:02","slug":"how-to-insert-query-and-modify-data-in-postgresql-getting-started-with-postgresql-part-three","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/how-to-insert-query-and-modify-data-in-postgresql-getting-started-with-postgresql-part-three\/","title":{"rendered":"How to insert, query, and modify data in PostgreSQL (getting started with PostgreSQL, part three)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>Once your PostgreSQL tables are built, the next step is putting them to work. This guide walks through the core data operations every PostgreSQL user needs: inserting records with <code>INSERT<\/code>, retrieving them with <code>SELECT<\/code>, filtering and combining tables with <code>WHERE<\/code> and <code>JOIN<\/code>, and modifying or removing data with <code>UPDATE<\/code> and <code>DELETE<\/code>. <\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>You&#8217;ll also learn how PostgreSQL handles <code>IDENTITY<\/code> columns, sequences, aliases, and referential integrity<\/strong>.<\/p>\n\n\n\n<div id=\"callout-block_8ec2eee3ec8d7752048e470ffda69fe6\" class=\"callout alignnone\">\n    <div class=\"child-last:mb-0 child-first:mt-0 bg-gray-50 dark:bg-gray-950 p-4xl my-3xl\">\n\n<p class=\"wp-block-paragraph\"><strong>Important note before you continue&#8230;<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is the third and final part in Grant Fritchey&#8217;s complete set of step-by-step walkthroughs (guides) for getting started with PostgreSQL, designed for any IT professional or hobbyist who wants to add PostgreSQL to their existing skillset. <a href=\"https:\/\/www.red-gate.com\/simple-talk\/collections\/how-to-get-started-with-postgresql-a-complete-set-of-hands-on-classes\/\" target=\"_blank\" rel=\"noreferrer noopener\">Click here for the full series<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Originally intended to be proctored classes given in a live, in-person environment, Grant has aimed to make the documentation and scripts clear enough to walk through them independently from home.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before getting started, please check that you have <a href=\"https:\/\/www.red-gate.com\/simple-talk\/collections\/how-to-get-started-with-postgresql-a-complete-set-of-hands-on-classes\/#:~:text=What%20do%20I%20need%20to%20follow%20this%20walkthrough%3F\" target=\"_blank\" rel=\"noreferrer noopener\">everything you need.<\/a><\/p>\n\n<\/div>\n<\/div> \n\n\n<h2 id=\"h-how-to-insert-add-data-to-postgresql\" class=\"wp-block-heading\">How to insert (add) data to PostgreSQL<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>With tables in place, we can now add data our <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/\" target=\"_blank\" rel=\"noreferrer noopener\">PostgreSQL<\/a> databases.<\/strong> First, I&#8217;ll run through a few manual <code>INSERT<\/code> statements to show some of the behaviors. These scripts will be in&nbsp;<code>addingdata_manual.sql<\/code> &#8211;&nbsp;however, most of the data will get added by running just one script&nbsp;(<code>addingdata.sql<\/code>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before we start, make sure you&#8217;re logged in to <code>psql<\/code>: <code>psql -d ham_shack -h localhost -U radiodev<\/code><\/p>\n\n\n\n<h3 id=\"h-the-postgresql-insert-statement\" class=\"wp-block-heading\">The PostgreSQL <code>INSERT<\/code> statement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The basic behavior of the <code>INSERT<\/code> statement is pretty common across most data platforms. You define the <a href=\"https:\/\/www.postgresql.org\/docs\/current\/ddl-basics.html\" target=\"_blank\" rel=\"noreferrer noopener\">table<\/a> you&#8217;re going to add data to. You then supply a list of columns in that table. Finally, you supply values for those columns. <\/p>\n\n\n\n<div id=\"callout-block_8ec2eee3ec8d7752048e470ffda69fe6\" class=\"callout alignnone\">\n    <div class=\"child-last:mb-0 child-first:mt-0 bg-gray-50 dark:bg-gray-950 p-4xl my-3xl\">\n\n<p class=\"wp-block-paragraph\"><strong>The <code>INSERT<\/code> statement across various data platforms: further reading<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/learn\/working-with-the-insert-statement-in-sql-server\/\" target=\"_blank\" rel=\"noreferrer noopener\">Working with the INSERT statement in SQL Server<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/learn\/the-basics-of-inserting-data-into-a-sql-server-table\/\" target=\"_blank\" rel=\"noreferrer noopener\">The Basics of Inserting Data into a SQL Server Table<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/introducing-the-mysql-insert-statement\/\" target=\"_blank\" rel=\"noreferrer noopener\">Introducing the MySQL INSERT statement<\/a><\/p>\n\n<\/div>\n<\/div> \n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s an example for the&nbsp;<code>gear.antenna<\/code>&nbsp;table:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">INSERT INTO gear.antenna \n(antenna_name)\nVALUES\n('Rubber duck');<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This follows exactly what we described above. The only thing to point out here is that we didn&#8217;t include the&nbsp;<code>antenna_id<\/code>&nbsp;column, since that&#8217;s set as an&nbsp;<a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/identity-columns\/\" target=\"_blank\" rel=\"noreferrer noopener\"><code>IDENTITY<\/code>&nbsp;column<\/a> and will, by default, create its own values. So, there&#8217;s no need to add it to the column list. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, if you want to <em>override<\/em> the behavior of&nbsp;<code>IDENTITY<\/code>,&nbsp;you can simply supply it. Just make sure you&#8217;re not violating the <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/learn\/primary-key-primer-for-sql-server\/\" target=\"_blank\" rel=\"noreferrer noopener\">primary key<\/a> or you&#8217;ll get an error. <em>Don&#8217;t<\/em> run this script, for example:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">INSERT INTO gear.antenna \n(antenna_id,antenna_name)\nVALUES\n(2,'Signal Stick');<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">While this <em>would<\/em> technically work, it won&#8217;t reset the values on the&nbsp;<code>IDENTITY<\/code>&nbsp;column &#8211; you&#8217;ll get an error at the next&nbsp;<code>INSERT<\/code>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, you have to <em>manually<\/em> add data to an&nbsp;<code>IDENTITY<\/code>&nbsp;column that is less than the current value of the&nbsp;<code>SEQUENCE<\/code>&nbsp;(the underlying architecture of the&nbsp;<code>IDENTITY<\/code>&nbsp;behavior). Otherwise, you&#8217;d have to manually update the latest value for the&nbsp;<code>SEQUENCE<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You don&#8217;t have to supply the column names. You can leave them off the&nbsp;<code>INSERT<\/code>&nbsp;statement entirely:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">INSERT INTO gear.antenna \nVALUES\n(DEFAULT, 'Signal Stick');<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">In order to skip the column list, you must have the right number of columns, in the right order, with the right data types, in your&nbsp;<code>VALUES<\/code>&nbsp;list. If not, you&#8217;ll get an error. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We also don&#8217;t want to mess up the <code>IDENTITY<\/code> value, we have to use the&nbsp;<code>DEFAULT<\/code>&nbsp;keyword, which triggers PostgreSQL to supply the value. For a very small table like&nbsp;<code>gear.antenna<\/code> &#8211; which by default only needs a single column -this is fine. However, it&#8217;d likely cause issues with larger tables.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can also add more than one value &#8211; in this case, three rows are added to the table with:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">INSERT INTO gear.antenna \n(antenna_name)\nVALUES\n('ZBM2 All Weather Whip'),\n('Maximus'),\n('771');<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Speaking of rows, the <a href=\"https:\/\/www.postgresql.org\/docs\/\" target=\"_blank\" rel=\"noreferrer noopener\">PostgreSQL documentation<\/a> uses both &#8216;tuple&#8217; <em>and<\/em> &#8216;row&#8217; to describe rows. Tuple is a much more academic term but, to be clear, they both mean the same thing.<\/p>\n\n\n\n<h3 id=\"h-filling-out-the-rest-of-the-data\" class=\"wp-block-heading\">Filling out the rest of the data<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s exit interactive <code>psql<\/code> for the moment (using <code>\\q<\/code>), and we&#8217;ll now load data into the remaining tables by running the <code>addingdata.sql<\/code> script.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, copy it to the container volume. As covered previously in the guide, use the File app in Linux, File Explorer in Windows, or issue a <a href=\"https:\/\/www.lenovo.com\/gb\/en\/glossary\/command-line\/#:~:text=The%20command%20line%20refers%20to,with%20a%20computer's%20operating%20system.\" target=\"_blank\" rel=\"noreferrer noopener\">command line<\/a> to copy the file. Once done, execute it through <code>psql<\/code> by using<br><code>psql -d postgres -h localhost -U postgres -f \"\/var\/lib\/postgresql\/bu\/addingdata.sql\"<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once complete, you&#8217;ll have a little bit of data in every table. One point from the script: the final way you can&nbsp;<code>INSERT<\/code>&nbsp;data is to combine it with a&nbsp;<code>SELECT<\/code>. The following query will run with the script, so no need to execute it. It shows how an&nbsp;<code>INSERT<\/code>&nbsp;and a&nbsp;<code>SELECT<\/code>&nbsp;can be combined:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">INSERT INTO gear.radio_antenna\n(radio_id, antenna_id)\nSELECT r.radio_id, a.antenna_id\nFROM gear.radio r\nCROSS JOIN gear.antenna a;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Since there&#8217;s no&nbsp;<code>WHERE<\/code>&nbsp;clause <em>and<\/em> it&#8217;s doing a&nbsp;<code><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/understanding-sql-join-types\/#:~:text=last%20two%20rows.-,Cross%20Join%3A,-Cross%20join%20(also\" target=\"_blank\" rel=\"noreferrer noopener\">CROSS JOIN<\/a><\/code>, every antenna is combined with every radio.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And we&#8217;re done! Now that we have data in the tables, we can proceed to <em>query<\/em> that data. <\/p>\n\n\n\n<h2 id=\"h-how-to-query-data-in-postgresql\" class=\"wp-block-heading\">How to query data in PostgreSQL<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In this section, I&#8217;ll walk through several different PostgreSQL queries, showing a few of the distinctions in how they operate compared to other platforms. This won&#8217;t be a complete guide on querying PostgreSQL &#8211; rather, just introduction to the fundamentals. If you <em>do<\/em> want more detail, <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/querying-postgresql-learning-postgresql-with-grant\/\" target=\"_blank\" rel=\"noreferrer noopener\">click here for my full guide to querying PostgreSQL<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before we start querying, be sure you&#8217;re logged in to&nbsp;<code>psql<\/code>&nbsp;as the role&nbsp;<code>radiodev<\/code>:<br><code>psql -d ham_shack -h localhost -U radiodev<\/code><\/p>\n\n\n\n<h3 id=\"h-how-to-retrieve-data-from-postgresql-with-the-select-statement\" class=\"wp-block-heading\">How to retrieve data from PostgreSQL with the <code>SELECT<\/code> statement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>PostgreSQL adheres fairly strictly to the <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/oracle-databases\/ansi-sql\/\" target=\"_blank\" rel=\"noreferrer noopener\">ANSI SQL<\/a> standard, which includes the use of the <code>SELECT<\/code> statement to retrieve data. <\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The most simple query is <code>SELECT * FROM radio;<\/code>, in which the <code>*<\/code> retrieves all columns. You have to define the tables you&#8217;re accessing through the <code>FROM<\/code> clause of the query. However, this isn&#8217;t the best way to write queries. Why? <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, and most importantly, I didn&#8217;t define the schema. It happens that the&nbsp;<code>search_path<\/code>&nbsp;(defined earlier in the guide) put the&nbsp;<code>gear<\/code>&nbsp;schema first &#8211; hence the correct table was found. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, the use of&nbsp;<code>*<\/code>&nbsp;is considered bad practice, since you&#8217;re not actually controlling specifically which columns you&#8217;re interested in, or their order. A better way to write the same query is:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">SELECT\n\tradio_id,\n\tradio_name,\n\tbrand\nFROM\n\tgear.radio;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Note that plenty of white space, tabs, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Carriage_return\" target=\"_blank\" rel=\"noreferrer noopener\">carriage returns<\/a>, and spaces are ignored by the query engine in PostgreSQL. To make the code easier to read, I format it with the carriage returns, etc, but this is optional of course. You could write the query as one long line and it would work the same &#8211; it&#8217;s just more difficult to read:<br><code>SELECT radio_id,radio_name,brand FROM gear.radio;<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s the output from any of the three queries defined so far:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \"> radio_id | radio_name |       brand       \n----------+------------+-------------------\n        1 | Maverick   | BridgeCom Systems\n        2 | DM32-UV    | Baofeng\n        3 | FT3D       | Yaesu\n(3 rows)<\/pre><\/div>\n\n\n\n<h3 id=\"h-the-where-clause-in-postgresql\" class=\"wp-block-heading\">The <code>WHERE<\/code> clause in PostgreSQL<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Another important point is to filter data through the use of the <code>WHERE<\/code> clause. For example, if we want to <em>only<\/em> retrieve information about the &#8216;Maverick&#8217; radio, we could do:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">SELECT\n\tbrand\nFROM\n\tgear.radio\nWHERE\n\tradio_id = 1;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This leads to a much-reduced result set:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">       brand       \n-------------------\n BridgeCom Systems<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>WHERE<\/code> clause supports logical operators as well. We could supply an&nbsp;<code>OR<\/code>&nbsp;in the&nbsp;<code>WHERE<\/code>&nbsp;clause like this:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">SELECT\n\tlast_name\nFROM\n\tpeople.operator\nWHERE\n\tfirst_name = 'Grant'\n\tOR first_name = 'Howard';<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Resulting in:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \"> last_name \n-----------\n Fritchey\n Hawkins<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike the integer value of&nbsp;<code>1<\/code>&nbsp;up above (for the <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/find-and-replace-text-in-strings-in-t-sql\/\" target=\"_blank\" rel=\"noreferrer noopener\">strings<\/a>), we&#8217;ve used a single quote <em>around<\/em> the string. It&#8217;s how PostgreSQL separates this from another <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/common-sql-server-problems-invalid-object-name\/\" target=\"_blank\" rel=\"noreferrer noopener\">object or function name<\/a>. The other logical operators are&nbsp;<code>AND<\/code>&nbsp;and&nbsp;<code>NOT<\/code>. You can make increasingly more complex queries with these.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before continuing with that, though, let&#8217;s add more tables to our queries through the <code>JOIN<\/code> operator.<\/p>\n\n\n\n<section id=\"my-first-block-block_ffc0d09ded762ba0dfb17911454d41d0\" class=\"my-first-block alignwide\">\n    <div class=\"bg-brand-600 text-base-white py-5xl px-4xl rounded-sm bg-gradient-to-r from-brand-600 to-brand-500 red\">\n        <div class=\"gap-4xl items-start md:items-center flex flex-col md:flex-row justify-between\">\n            <div class=\"flex-1 col-span-10 lg:col-span-7\">\n                <h3 class=\"mt-0 font-display mb-2 text-display-sm\">Get started with PostgreSQL &#8211; free book download<\/h3>\n                <div class=\"child:last-of-type:mb-0\">\n                                            &#8216;Introduction to PostgreSQL for the data professional&#8217;, written by Grant Fritchey and Ryan Booz, covers all the basics of how to get started with PostgreSQL.                                    <\/div>\n            <\/div>\n                                            <a href=\"https:\/\/www.red-gate.com\/hub\/books\/introduction-to-postgresql-for-the-data-professional\/\" class=\"btn btn--secondary btn--lg\" aria-label=\"Download your free copy: Get started with PostgreSQL - free book download\">Download your free copy<\/a>\n                    <\/div>\n    <\/div>\n<\/section>\n\n\n<h3 id=\"h-the-join-operator-in-postgresql\" class=\"wp-block-heading\">The <code>JOIN<\/code> operator in PostgreSQL<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><a href=\"https:\/\/azure.microsoft.com\/en-us\/resources\/cloud-computing-dictionary\/what-is-postgresql#:~:text=PostgreSQL%20definition\" target=\"_blank\" rel=\"noreferrer noopener\">PostgreSQL is an object-relational data store<\/a>, and a relational storage engine lives on the <em>relationships between tables<\/em>.<\/strong> <strong>We defined those relationships when we created foreign keys and, to put tables together, we use the <code>JOIN<\/code> operator.<\/strong> <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In addition to this, however, we need to define the owners. This is so the <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/how-to-troubleshoot-and-fix-postgresql-performance-issues\/#:~:text=Although%20Postgres%20has%20a%20powerful%20optimizer%20and%20can%20fix%20performance%20issues%20for%20you%2C%20sometimes%20you%20have%20to%20tweak%20your%20query%20to%20improve%20your%20query%20performance.%20You%20will%20find%20why%20in%20the%20next%20section.\" target=\"_blank\" rel=\"noreferrer noopener\">PostgreSQL optimizer<\/a> knows which table we&#8217;re pulling columns from. A query to retrieve radio and antenna names might look like:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">SELECT\n\tradio.radio_name,\n\tantenna.antenna_name\nFROM\n\tgear.radio\nJOIN gear.radio_antenna\nON\n\tradio.radio_id = radio_antenna.radio_id\nJOIN gear.antenna\nON\n\tradio_antenna.antenna_id = antenna.antenna_id\nWHERE\n\tradio.radio_id = 1;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">There are several points to take from this. First, we&#8217;re supplying the table name for each column now. This has to happen because two tables contain a <code>radio_id<\/code> column (in the form of <code>radio<\/code>&nbsp;and&nbsp;<code>radio_antenna<\/code>), and another two tables contain an&nbsp;<code>antenna_id<\/code>&nbsp;column with&nbsp;<code>antenna<\/code>&nbsp;and&nbsp;<code>radio_antenna<\/code>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Second, we&#8217;ve added two more words to the query language: <code>JOIN<\/code>&nbsp;and&nbsp;<code>ON<\/code>.&nbsp;<code>JOIN<\/code>&nbsp;defaults to&nbsp;<code><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/understanding-sql-join-types\/#:~:text=through%20some%20examples.-,Inner%20Join,-An%20inner%20join\" target=\"_blank\" rel=\"noreferrer noopener\">INNER JOIN<\/a><\/code>. The&nbsp;<code>INNER<\/code>&nbsp;is <a href=\"https:\/\/en.wikipedia.org\/wiki\/Syntactic_sugar\" target=\"_blank\" rel=\"noreferrer noopener\">syntactic sugar<\/a> and not really needed. PostgreSQL supports&nbsp;<code>LEFT<\/code>&nbsp;and&nbsp;<code>RIGHT<\/code>&nbsp;joins as well. You can simply use&nbsp;<code>LEFT JOIN<\/code>&nbsp;instead of the more traditional&nbsp;<code>LEFT OUTER JOIN<\/code> to, again, eliminate syntactic sugar. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<code>LEFT<\/code>&nbsp;or&nbsp;<code>RIGHT<\/code>&nbsp;join will return <code><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/empty-thoughts-working-with-null\/\" target=\"_blank\" rel=\"noreferrer noopener\">NULL<\/a><\/code> values on non-matching rows.&nbsp;<code>JOIN<\/code>&nbsp;is how you tell which tables you&#8217;re going to add to the query. Then,&nbsp;<code>ON<\/code>&nbsp;is used to define the criteria for joining between the tables. In our case, we used the primary key from one table to join to the foreign key in the other.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To my eye, that query is quite hard to read because of all the table names, which isn&#8217;t unusual. Thankfully, PostgreSQL supports the use of aliases. So, to see my radio contacts for example, I could query like this:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">SELECT\n\tol.callsign,\n\tol.first_name,\n\tc.contact_date,\n\tc.freq_mhz,\n\tr.radio_name\nFROM\n\tpeople.operator o\nJOIN people.contact c \nON\n\to.operator_id = c.call_operator_id\nJOIN people.operator ol \nON\n\tc.logged_operator_id = ol.operator_id\nJOIN gear.radio r \nON\n\tc.radio_id = r.radio_id\nWHERE\n\to.callsign = 'KC1KCE';<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This query then puts it all together and we&#8217;re still appropriately using both the schema <em>and<\/em> <a href=\"https:\/\/www.red-gate.com\/simple-talk\/featured\/postgresql-basics-object-ownership-and-default-privileges\/\" target=\"_blank\" rel=\"noreferrer noopener\">object ownership<\/a>. However, by defining aliases (<code>people.operator o<\/code>), we can use a much shorter object <em>&#8220;owner&#8221;<\/em>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Again, PostgreSQL doesn&#8217;t need to use the full syntax for aliases,&nbsp;<code>people.operator AS o<\/code>. We&#8217;ve also crossed between schemas, referencing both&nbsp;<code>gear<\/code>&nbsp;and&nbsp;<code>people<\/code>. The results should look something like:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \"> callsign | first_name |    contact_date     |  freq_mhz  | radio_name \n----------+------------+---------------------+------------+------------\n GG7WXYZ  | Reginald   | 2026-07-02 13:33:00 | 146.500000 | Maverick\n DD8AAAAB | Horst      | 2026-07-02 13:35:00 | 146.500000 | Maverick\n VK39AA   | GDay       | 2026-07-02 13:38:00 | 146.500000 | Maverick\n K5ABCD   | Howard     | 2026-07-02 13:39:00 | 146.500000 | Maverick<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s add one more bit of syntax to our querying: placing the data in order.<\/p>\n\n\n\n<h3 id=\"h-how-to-use-order-by-to-order-data-in-postgresql\" class=\"wp-block-heading\">How to use <code>ORDER BY<\/code> to order data in PostgreSQL<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>It&#8217;s common to want to control the order of data, and PostgreSQL never determines the order unless you specify it. So, running one query on different days could return the data in a different order, depending on how it&#8217;s stored. This is why syntax to determine the order is so important.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, to see frequencies in the&nbsp;<code>people.contact<\/code>&nbsp;table, we need to put them in order:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">SELECT\n\tc.freq_mhz,\n\tr.radio_name\nFROM\n\tpeople.contact c\nJOIN gear.radio r \nON\n\tc.radio_id = r.radio_id\nORDER BY\n\tc.freq_mhz;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><code>ORDER BY<\/code>&nbsp;will, by default, place things in <em>ascending<\/em> order:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">  freq_mhz  | radio_name \n------------+------------\n 146.500000 | Maverick\n 146.500000 | Maverick\n 146.500000 | Maverick\n 146.500000 | Maverick\n 147.500000 | DM32-UV\n 147.500000 | DM32-UV\n 147.500000 | DM32-UV\n 147.500000 | DM32-UV\n 446.000000 | FT3D\n 462.375000 | Maverick<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">From there, you can control the order <em>and<\/em> the number of rows returned:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">SELECT\n\tc.freq_mhz,\n\tr.radio_name\nFROM\n\tpeople.contact c\nJOIN gear.radio r \nON\n\tc.radio_id = r.radio_id\nORDER BY\n\tc.freq_mhz DESC\nLIMIT 5;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">I added&nbsp;<code>DESC<\/code>&nbsp;after the column to tell it to go in <em>descending<\/em> order. Then, using&nbsp;<code>LIMIT 5<\/code> ensures that only five rows are returned:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">  freq_mhz  | radio_name \n------------+------------\n 462.375000 | Maverick\n 446.000000 | FT3D\n 147.500000 | DM32-UV\n 147.500000 | DM32-UV\n 147.500000 | DM32-UV<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">You <em>can<\/em> use&nbsp;<code>LIMIT<\/code>&nbsp;without an&nbsp;<code>ORDER BY<\/code>but, again, you won&#8217;t be able to guarantee which five (or however many) rows you&#8217;ll see.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s some of the very basics of querying PostgreSQL for you, but there&#8217;s so much more we <em>didn&#8217;t<\/em> touch upon. As mentioned earlier, see my <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/querying-postgresql-learning-postgresql-with-grant\/\" target=\"_blank\" rel=\"noreferrer noopener\">full guide<\/a> for more.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As for what&#8217;s next, we&#8217;ll now take a look at data manipulation in PostgreSQL. By the end, you&#8217;ll know how to change and remove data from your PostgreSQL databases.<\/p>\n\n\n\n<h2 id=\"h-how-to-modify-manipulate-data-in-postgresql\" class=\"wp-block-heading\">How to modify\/manipulate data in PostgreSQL<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As usual, make sure you&#8217;re connected to <code>psql<\/code> before continuing: <code>psql -d ham_shack -h localhost -U radiodev<\/code><\/p>\n\n\n\n<h3 id=\"h-the-update-statement-in-postgresql\" class=\"wp-block-heading\">The <code>UPDATE<\/code> statement in PostgreSQL<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<code>UPDATE<\/code>&nbsp;statement syntax is extremely simple. You can only modify one table at a time, so you define the table you wish to change, then define the column(s) you&#8217;re changing. Finally, filter with a <code>WHERE<\/code> clause:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">UPDATE\n\tpeople.operator\nSET\n\tlast_name = 'Smith'\nWHERE\n\tcallsign = 'GG7WXYZ';<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\" id=\"h-how-to-modify-manipulate-data-in-postgresql\"><a href=\"https:\/\/github.com\/ScaryDBA\/GettingStartedWithPostgreSQL\/blob\/main\/11.%20Modifying%20Data\/modifyingdata.md#modifying-data-in-postgresql\"><\/a>The last bit is the most important. You don&#8217;t have to use a <code>WHERE<\/code> clause but, if we&#8217;d left it off this query, every value in the column&nbsp;<code>last_name<\/code>&nbsp;would be changed to &#8216;Smith&#8217;. It&#8217;s not uncommon to do this intentionally, but it&#8217;s also <em>very<\/em> easy to do so accidentally. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\" id=\"h-how-to-modify-manipulate-data-in-postgresql\">So, BE CAUTIOUS! <strong>If your <code>WHERE<\/code> clauses matches multiple rows in the table, multiple rows will be updated.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When you execute the query through <code>psql<\/code>, you get a single line back &#8211; <code>UPDATE 1<\/code>&#8211; letting you know what you did and how many rows it affected.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want to update more than one column, simply add them to the&nbsp;<code>SET<\/code>&nbsp;part of the statement:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">UPDATE \n\tpeople.operator\nSET\n\tfirst_name = 'Bob',\n\tlast_name = 'McCall'\nWHERE\n\tcallsign = 'VK39AA';<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">You can also add a&nbsp;<code>FROM<\/code>&nbsp;clause to the query, with which you can then&nbsp;<code>JOIN<\/code>&nbsp;to multiple tables. You&#8217;d do this to perform an&nbsp;<code>UPDATE<\/code>&nbsp;based on other data within the database. However, you&#8217;re still only ever updating one table at a time. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, you can also use aliases for the table names &#8211; including the one being updated.<\/p>\n\n\n\n<h3 id=\"h-the-delete-statement-in-postgresql\" class=\"wp-block-heading\">The <code>DELETE<\/code> statement in PostgreSQL<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s add a couple of rows, just so we can remove them later for a demonstration of how to delete data in PostgreSQL:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">INSERT\n\tINTO\n\tgear.antenna \n(antenna_name)\nVALUES\n('End fed half wave'),\n('Dipole'),\n('Fan');<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Like&nbsp;<code>UPDATE<\/code>,&nbsp;the <code>DELETE<\/code>&nbsp;statement in PostgreSQL is a single-table operation.<\/strong> The syntax is quite simple as well:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">DELETE\nFROM\n\tgear.antenna\nWHERE\n\tantenna_name = 'Fan';<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">As with&nbsp;<code>UPDATE<\/code>, if you leave off the&nbsp;<code>WHERE<\/code>&nbsp;clause, wave goodbye to your data. When run, we get what we did, and the number of rows affected (similar to <code>UPDATE<\/code>): <code>DELETE 1<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But what if we wanted to get rid of the very first row in the&nbsp;<code>antenna<\/code>&nbsp;table? We&#8217;d run:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">DELETE\nFROM\n\tgear.antenna \nWHERE\n\tantenna_id = 1;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">&#8230;which <em>should <\/em>return the error:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">ERROR:  update or delete on table \"antenna\" violates foreign key constraint \"radio_antenna_antenna_id_fkey\" on table \"radio_antenna\"\nDETAIL:  Key (antenna_id)=(1) is still referenced from table \"radio_antenna\".<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Since we have <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/do-you-have-references\/\" target=\"_blank\" rel=\"noreferrer noopener\">referential integrity<\/a> in our database through the definition of foreign keys, we can&#8217;t just delete data that is in use; there&#8217;s a <em>validation<\/em> before the&nbsp;<code>DELETE<\/code>&nbsp;occurs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s run one more&nbsp;<code>DELETE<\/code>&nbsp;statement (just so we can see how more than one row is affected):<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">DELETE\nFROM\n\tgear.antenna\nWHERE\n\tantenna_id &gt; 5;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This returns <code>DELETE 2<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can also reference other tables in a&nbsp;<code>DELETE<\/code>&nbsp;statement with the&nbsp;<code>USING<\/code>&nbsp;clause. However, you&#8217;re again still only deleting from a <em>single table<\/em>. The other tables are to provide a more sophisticated filtering mechanism based on data in the database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One final note on&nbsp;<code>UPDATE<\/code>&nbsp;and&nbsp;<code>DELETE<\/code>. In PostgreSQL, by default, when you modify or remove a row, you&#8217;re not <em>really<\/em> doing either of those things. In the case of both statements, the previous row is marked as <em>logically deleted<\/em>, and a new row is inserted into the table. No physical delete occurs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is all part of the <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/multi-version-concurrency-control-mvcc-in-postgresql-learning-postgresql-with-grant\/\" target=\"_blank\" rel=\"noreferrer noopener\">Multi-Version Concurrency Control (MVCC)<\/a>, the mechanism within PostgreSQL that makes it so that readers seldom block writers, and writers seldom block readers. A process called <code><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/learning-postgresql-with-grant-introducing-vacuum\/\" target=\"_blank\" rel=\"noreferrer noopener\">VACUUM<\/a><\/code> effectively &#8216;cleans up&#8217; the logically-deleted rows, ultimately removing them from the system.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">From here, there&#8217;s just one more (somewhat optional) thing I want to teach: how to set up the Bluebox sample database in PostgreSQL. Let&#8217;s get into it.<\/p>\n\n\n\n<h2 id=\"h-how-to-set-up-the-bluebox-sample-database-in-postgresql-and-why-you-should\" class=\"wp-block-heading\">How to set up the Bluebox sample database in PostgreSQL (and why you should)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><a href=\"https:\/\/www.red-gate.com\/simple-talk\/author\/ryan-booz\/\" target=\"_blank\" rel=\"noreferrer noopener\">Ryan Booz<\/a> created a fantastic PostgreSQL sample database, <a href=\"https:\/\/github.com\/ryanbooz\/bluebox\" target=\"_blank\" rel=\"noreferrer noopener\">Bluebox<\/a>. It represents a DVD rental kiosk (similar to the real one in the US, Redbox) and has a very sophisticated set of real data, tables, extensions, and more. It&#8217;s available as a dump that you can add to your own PostgreSQL cluster, or can be run as a container. <\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(In the container, <a href=\"https:\/\/github.com\/citusdata\/pg_cron\" target=\"_blank\" rel=\"noreferrer noopener\">pg_cron<\/a> (a scheduling utility) runs scripts that simulate a real load.)<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before setting up Bluebox, I want to first <strong>show you how to clean up your PostgreSQL containers.<\/strong><\/p>\n\n\n\n<h3 id=\"h-how-to-remove-postgresql-containers\" class=\"wp-block-heading\">How to remove PostgreSQL containers<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Containers are meant to live short lives. It&#8217;s normal to throw them out regularly and then start them back up again. Just remember, use volumes when you do so you can retain information once the container is gone.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you&#8217;re still logged in to <code>psql,<\/code> run <code>\\q<\/code>, then exit the Bash container with <code>exit<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>In PostgreSQL, you can only remove a container when it&#8217;s stopped, so step one is to stop the container<\/strong>:<br><code>docker stop StartingPostgreSQL<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With the container stopped, you can now remove it with <code>docker rm StartingPostgreSQL<\/code>. This removes the container and <em>everything<\/em> in it &#8211; the only exception being anything stored in the local folder that you used as a volume.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The image will be retained unless you remove it too. To see the images on your machine, run <code>docker images<\/code>. You should see one called <code>postgres:latest<\/code> &#8211; the one we want to remove. To do so, use <code>docker rmi postgres:latest.<\/code> <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And that&#8217;s it! Now, back to Bluebox.<\/p>\n\n\n\n<h3 id=\"h-how-to-set-up-the-bluebox-sample-database-in-postgresql\" class=\"wp-block-heading\">How to set up the Bluebox sample database in PostgreSQL<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To set up Bluebox in PostgreSQL, first head to the <a href=\"https:\/\/github.com\/ryanbooz\/bluebox\" target=\"_blank\" rel=\"noreferrer noopener\">official GitHub repo<\/a> if you haven&#8217;t already. Then, with whatever command line utility you&#8217;re using, navigate to the folder where you&#8217;re storing your Git repos, and clone the Bluebox one with <code>git clone https:\/\/github.com\/ryanbooz\/bluebox-docker.git<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This will take several minutes, using around 338mb of storage. Once it&#8217;s done, change to the&nbsp;<code>bluebox-docker<\/code>&nbsp;folder: <code>cd bluebox-docker<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then, it&#8217;s easy. Ryan even included a shell script:<code> .\/start.sh<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The shell script walks you through selecting the version of PostgreSQL you need, and the port to install it to. If you&#8217;re still running the&nbsp;<code>StartingPostgreSQL<\/code>&nbsp;container, it&#8217;ll be using port 5432, so stop the container or pick another port:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:tsql decode:true \">Available versions: 14, 15, 16, 17, 18, 19-dev\nPostgres version [18]: 18\nHost port [5432]: \n\n----------------------------------------\nConfiguration:\n  Postgres version: 18\n  Host port:        5432\n  Project name:     bluebox-pg18\n----------------------------------------<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Then, it will download the docker image, start the container, and load the database, all completely automatically. This step also takes several minutes on a good internet connection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When you&#8217;re done, you&#8217;ll have a running container with Bluebox in it. The roles for connecting are as follows:<a href=\"https:\/\/github.com\/ScaryDBA\/GettingStartedWithPostgreSQL\/blob\/main\/12.%20Setting%20Up%20Bluebox\/bluebox.md#removing-containers\"><\/a><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Role<\/th><th>Password<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td>bb_app<\/td><td>app_password<\/td><td>Application queries<\/td><\/tr><tr><td>bb_admin<\/td><td>admin_password<\/td><td>Schema admin<\/td><\/tr><tr><td>postgres<\/td><td>password<\/td><td>Superuser (use sparingly!)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Ryan&#8217;s script even helpfully pops out a <code>psql<\/code> connection string: <code>psql -h localhost -p 5432 -U bb_admin -d bluebox<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And that&#8217;s it for the series! You have been introduced to PostgreSQL. Have fun!<\/p>\n\n\n\n<div id=\"callout-block_8ec2eee3ec8d7752048e470ffda69fe6\" class=\"callout alignnone\">\n    <div class=\"child-last:mb-0 child-first:mt-0 bg-gray-50 dark:bg-gray-950 p-4xl my-3xl\">\n\n<p class=\"wp-block-paragraph\"><strong>Want to advance your PostgreSQL learning? Here&#8217;s what to read next on Simple Talk:<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.red-gate.com\/simple-talk\/collections\/series-learning-postgresql-with-grant\/\" target=\"_blank\" rel=\"noreferrer noopener\">Learning PostgreSQL with Grant &#8211; the full series<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.red-gate.com\/simple-talk\/author\/ryan-booz\/\" target=\"_blank\" rel=\"noreferrer noopener\">Ryan Booz&#8217;s PostgreSQL guides<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/postgresql\/\" target=\"_blank\" rel=\"noreferrer noopener\">The full collection of PostgreSQL articles and guides on Simple Talk<\/a><\/p>\n\n<\/div>\n<\/div> \n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>FAQs<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. How do you insert data into a PostgreSQL table?<\/h3>\n            <div class=\"faq-answer\">\n                <p dir=\"ltr\">Use the <code>INSERT INTO<\/code> statement, specifying the table name, an optional column list, and the values to add. If a column uses IDENTITY, you can omit it and let PostgreSQL auto-generate the value, or use the <code>DEFAULT<\/code> keyword to skip it explicitly while still listing all columns.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. Can you insert multiple rows in a single PostgreSQL query?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Yes. List multiple sets of values separated by commas within a single <code>INSERT INTO ... VALUES<\/code> statement to add several rows at once.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. Why shouldn&#039;t you use SELECT * in PostgreSQL queries?<\/h3>\n            <div class=\"faq-answer\">\n                <p><code>SELECT *<\/code> retrieves every column in an undefined order, which can affect performance and readability. Explicitly naming columns gives you control over which data is returned and in what order.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">4. What&#039;s the difference between UPDATE and DELETE in PostgreSQL, and are they permanent?<\/h3>\n            <div class=\"faq-answer\">\n                <p><code>UPDATE<\/code> modifies existing column values, while <code>DELETE<\/code> removes rows entirely \u2014 both operate on a single table at a time. Neither is truly immediate at the storage level: PostgreSQL&#8217;s MVCC system marks old rows as logically deleted and writes new ones, with the <code>VACUUM<\/code> process later cleaning them up.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">5. Why does PostgreSQL block deleting a row referenced by a foreign key?<\/h3>\n            <div class=\"faq-answer\">\n                <p>PostgreSQL enforces referential integrity, so deleting a row that&#8217;s still referenced by another table (via a foreign key) will throw an error unless the dependent rows are removed or updated first.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">6. How do you control the order and number of rows returned in a PostgreSQL query?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Use <code>ORDER BY<\/code> to sort results (ascending by default, or <code>DESC<\/code> for descending), and combine it with <code>LIMIT<\/code> to cap the number of rows returned. Without <code>ORDER BY<\/code>, row order isn&#8217;t guaranteed even when using <code>LIMIT<\/code>.<\/p>\n            <\/div>\n            <\/section>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to insert, query, update, and delete data in PostgreSQL with real examples covering INSERT, SELECT, JOIN, WHERE, and more.&hellip;<\/p>\n","protected":false},"author":221792,"featured_media":105920,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143523,53,143534],"tags":[4168,4170,159410,158978,4150,4252],"coauthors":[6785],"class_list":["post-112596","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-databases","category-featured","category-postgresql","tag-database","tag-database-administration","tag-gettingstartedpostgresgrant","tag-postgresql","tag-sql","tag-t-sql-programming"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/112596","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221792"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=112596"}],"version-history":[{"count":13,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/112596\/revisions"}],"predecessor-version":[{"id":113988,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/112596\/revisions\/113988"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media\/105920"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=112596"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=112596"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=112596"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=112596"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}