# Generating "INSERT INTO" SQL statement

**URL:** <https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106>\
**Category:** Data\
**Tags:** dataframes, postgresql\
**Created:** [April 12, 2021, 1:49pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106 "2021-04-12T13:49:34Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Laco\_Kovac](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laco_kovac/32/20684_2.png) [@Laco\_Kovac](https://discourse.julialang.org/u/Laco_Kovac)\
**Post date:** [April 12, 2021, 1:49pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/1 "2021-04-12T13:49:34Z")

</div>

I have either LibPQ.Result or DataFrame as an input, and as output I need to generate SQL statement in the form:

```julia
INSERT INTO table VALUES
(v1,v2,v3),
(v4,v5,v6);

```

I cannot use LibPQ.load! because I don’t want to execute the statement, only to generate it. There are limited column types, but still, they are quite diverse:

uuid  
string/varchars/text  
integer  
double  
json  
timestamp  
interval  
boolean

There will be missing values here & there, because some columns are nullable.

What would be the best/most efficient way to achieve this?

Thank you.

---

<div class="post-metadata">

**Author:** ![Laco\_Kovac](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laco_kovac/32/20684_2.png) [@Laco\_Kovac](https://discourse.julialang.org/u/Laco_Kovac)\
**Post date:** [April 13, 2021, 1:15pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/2 "2021-04-13T13:15:54Z")

</div>

This is the function I came up with, but I am not certain that there is not a better, more efficient way:

```julia
function generateInsertSql(conn::LibPQ.Connection, schemaName::String, tableName::String, resultSqlFullTableName::String)::String
    try
        executeResult = execute(conn, "SELECT * FROM $schemaName.$tableName")
        if !isempty(executeResult)
            frame = DataFrame(executeResult)
            numOfRows = size(frame, 1)
            iob = IOBuffer()
            Base.write(iob, "\nINSERT INTO $resultSqlFullTableName VALUES \n")
            for n in 1:numOfRows
                Base.write(iob, "(")
                bFirst::Bool = true
                for x in propertynames(frame)
                    if bFirst
                        bFirst = false
                    else
                        Base.write(iob, ",")
                    end
                    if isa(frame[!, x][n], Missing)
                        Base.write(iob, "NULL")
                    elseif isa(frame[!, x][n], Int32) || isa(frame[!, x][n], Float64) || isa(frame[!, x][n], Bool)
                        Base.write(iob, string(frame[!, x][n]))
                    elseif isa(frame[!, x][n], String)
                        Base.write(iob, "'$(replace(frame[!, x][n], "'" => "''"))'")
                    elseif isa(frame[!, x][n], DateTime)
                        Base.write(iob, "'$(Dates.format(frame[!, x][n], dateformat"yyyy-mm-dd HH:MM:SS.sss"))'")
                    elseif isa(frame[!, x][n], Date)
                        Base.write(iob, "'$(Dates.format(frame[!, x][n], dateformat"yyyy-mm-dd"))'")
                    elseif isa(frame[!, x][n], Time)
                        Base.write(iob, "'$(Dates.format(frame[!, x][n], dateformat"HH:MM:SS.sss"))'")
                    elseif isa(frame[!, x][n], Dates.CompoundPeriod)
                        Base.write(iob, compoundPeriodToString(frame[!, x][n]))
                    else
                        println(typeof(frame[!, x][n]))
                        Base.write(iob, frame[!, x][n])
                    end
                end
                if n === numOfRows
                    Base.write(iob, ");\n")
                else
                    Base.write(iob, "),\n")
                end
            end
            return String(take!(iob))
        end
    catch exc
        # do nothing
        println(exc)
        println("Didn't generate INSERT SQL for table $tableName.")
    end
    return ""
end

```

Could this be made better using somehow join or CSV.write, or something like that?

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [April 15, 2021, 3:13pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/3 "2021-04-15T15:13:22Z")

</div>

Your `if isa... elseif isa...` block begs for multiple dispatch

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [April 15, 2021, 4:04pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/4 "2021-04-15T16:04:36Z")

</div>

It’s basically union splitting here, so it is fine.

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [April 15, 2021, 4:20pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/5 "2021-04-15T16:20:06Z")

</div>

Fine in terms of what? Are you saying multiple dispatch wouldn’t work in this case?

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [April 15, 2021, 5:09pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/6 "2021-04-15T17:09:08Z")

</div>

It will work, but you wouldn’t get any benefits from it, since it will define types at runtime and as such it will be slower than current implementation. But it’ll look better and design will be more flexible, that’s true.

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [April 15, 2021, 5:23pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/7 "2021-04-15T17:23:45Z")

</div>

Thanks. When I made that suggestion I was concerned about cleanliness and maintainability. I wasn’t aware of performance implications.

---

<div class="post-metadata">

**Author:** ![Nosferican](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nosferican/32/9275_2.png) [@Nosferican](https://discourse.julialang.org/u/Nosferican)\
**Post date:** [April 15, 2021, 6:12pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/8 "2021-04-15T18:12:34Z")

</div>

Can you share a minimal reproducible example with the input and output? I would be happy to share my implementation with those.

---

<div class="post-metadata">

**Author:** ![Laco\_Kovac](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laco_kovac/32/20684_2.png) [@Laco\_Kovac](https://discourse.julialang.org/u/Laco_Kovac)\
**Post date:** [April 16, 2021, 8:31am UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/9 "2021-04-16T08:31:27Z")

</div>

I will provide one small example.  
Let’s have input table public.use\_cases, here is the structure:

```julia
CREATE TABLE public.use_cases
(
    id uuid NOT NULL DEFAULT uuid_generate_v4(),
    name character varying(150) COLLATE pg_catalog."default" NOT NULL,
    description text COLLATE pg_catalog."default",
    input text COLLATE pg_catalog."default",
    output text COLLATE pg_catalog."default",
    business_value text COLLATE pg_catalog."default",
    business_kpi text COLLATE pg_catalog."default",
    accuracy_impact integer,
    workspace_id uuid NOT NULL,
    dataset_id uuid,
    is_favorite boolean NOT NULL DEFAULT false,
    default_f_experiment uuid,
    default_ad_experiment uuid,
    created_at timestamp without time zone NOT NULL DEFAULT timezone('utc'::text, now()),
    created_by uuid NOT NULL,
    updated_at timestamp without time zone,
    updated_by uuid,
    business_objective text COLLATE pg_catalog."default",
    CONSTRAINT use_cases_pkey PRIMARY KEY (id)
)

```

Table has in reality also 6 foreign keys, but those are for our example irrelevant, so I don’t list those above.

You can fill it using SQL:

```julia
INSERT INTO public.use_cases VALUES
('ac7e086a-a7d5-4474-8ab4-e6b8c94994c7', 'Edited name', 'Edited description', 'Edited input', 'Edited output', 'test', 'test', 6, '3541ee59-d48e-4aaa-8f38-79554136462d', NULL, true, NULL, NULL, '2021-04-08 13:46:11.549539', 'b306ec38-ee19-4af5-9e3a-a36d2c22fe85', '2021-04-08 13:46:11.954205', 'b306ec38-ee19-4af5-9e3a-a36d2c22fe85', 'test'),
('d1197838-17c7-43c9-80f3-91d745ac32a8', 'xyz', NULL, NULL, NULL, NULL, NULL, NULL, '71ecb06c-2555-4f2b-9b99-d1dc9c0876ca', '07b18f7a-35b6-423d-b252-daf26d6e2e1c', false, NULL, NULL, '2021-03-17 13:17:18.743356', 'f31e650c-23b7-4886-a0a1-894c5eee9443', NULL, NULL, NULL),
('d726f6de-bd40-4c96-95c9-7bc080dab46d', '2 - with default exps', 'something else again', 'much data', '', '', '', NULL, '4e8fcfb2-4518-4445-afed-180941a0fd68', NULL, false, NULL, NULL, '2021-03-31 12:24:04.757653', '182b080b-8e42-4b85-82f5-e7e87bf8df0f', '2021-04-01 13:19:31.307656', '182b080b-8e42-4b85-82f5-e7e87bf8df0f', '');

```

Then you establish LibPQ connection conn and call this function as:

`generateInsertSql(conn, "public", "use_cases", "schema.table")`

And the result should roughly look like this:

```julia
INSERT INTO schema.table VALUES
('ac7e086a-a7d5-4474-8ab4-e6b8c94994c7', 'Edited name', 'Edited description', 'Edited input', 'Edited output', 'test', 'test', 6, '3541ee59-d48e-4aaa-8f38-79554136462d', NULL, true, NULL, NULL, '2021-04-08 13:46:11.549539', 'b306ec38-ee19-4af5-9e3a-a36d2c22fe85', '2021-04-08 13:46:11.954205', 'b306ec38-ee19-4af5-9e3a-a36d2c22fe85', 'test'),
('d1197838-17c7-43c9-80f3-91d745ac32a8', 'xyz', NULL, NULL, NULL, NULL, NULL, NULL, '71ecb06c-2555-4f2b-9b99-d1dc9c0876ca', '07b18f7a-35b6-423d-b252-daf26d6e2e1c', false, NULL, NULL, '2021-03-17 13:17:18.743356', 'f31e650c-23b7-4886-a0a1-894c5eee9443', NULL, NULL, NULL),
('d726f6de-bd40-4c96-95c9-7bc080dab46d', '2 - with default exps', 'something else again', 'much data', '', '', '', NULL, '4e8fcfb2-4518-4445-afed-180941a0fd68', NULL, false, NULL, NULL, '2021-03-31 12:24:04.757653', '182b080b-8e42-4b85-82f5-e7e87bf8df0f', '2021-04-01 13:19:31.307656', '182b080b-8e42-4b85-82f5-e7e87bf8df0f', '');

```

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [April 16, 2021, 9:09am UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/10 "2021-04-16T09:09:19Z")

</div>

Probably you aware of that, but it is much better to use prepared statements instead of generating these INSERT queries. First of all prepared statements are optimized and secondly they more secure. The current approach is vulnerable to [SQL injection attacks](https://en.wikipedia.org/wiki/SQL_injection).

We should always remember Bobby Tables

![](https://global.discourse-cdn.com/julialang/original/3X/9/6/96baa5b855cd9553b8507a43c1938ab9d7ec9e15.png)

---

<div class="post-metadata">

**Author:** ![Nosferican](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nosferican/32/9275_2.png) [@Nosferican](https://discourse.julialang.org/u/Nosferican)\
**Post date:** [April 17, 2021, 6:00pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/11 "2021-04-17T18:00:11Z")

</div>

I have some old code that does that but it didn’t work that well due to having to workaround all the sanitization issues (e.g., text that included special characters such as `'`). I still fail to understand the reason or use case for generating the SQL statement and not executing it which could allow you to use prepared statements.

---

<div class="post-metadata">

**Author:** ![wookyoung](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wookyoung/32/157_2.png) [@wookyoung](https://discourse.julialang.org/u/wookyoung)\
**Post date:** [April 17, 2021, 9:45pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/12 "2021-04-17T21:45:21Z")

</div>

I made a test for it using Octo.jl  
[https://github.com/wookay/Octo.jl/blob/master/test/adapters/postgresql/public\_use\_cases.jl](https://github.com/wookay/Octo.jl/blob/master/test/adapters/postgresql/public_use_cases.jl)

see that logs of the github actions.  
[https://github.com/wookay/Octo.jl/runs/2371398326?check\_suite\_focus=true#step:6:383](https://github.com/wookay/Octo.jl/runs/2371398326?check_suite_focus=true#step:6:383)

---

<div class="post-metadata">

**Author:** ![ImreSamu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/imresamu/32/20677_2.png) [@ImreSamu](https://discourse.julialang.org/u/ImreSamu)\
**Post date:** [April 18, 2021, 9:33am UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/13 "2021-04-18T09:33:12Z")

</div>

> I still fail to understand the reason or use case  
> for generating the SQL statement and not executing it

IMHO: it can be a core of flexible homemade database tool/scripts.

- executing later in time ( backup → restore )
  - just check the postgres `pg_dump` output.

- executing in a different ( unconnected? SQL database ) - as a security reason.
  - in this case - the target database administrator can validate/test the SQL insert script.

- executing the output in a multiple - different SQL architecture
  - so the “create table” part is not hardcoded … partitioning, special compression parameter can be added later.

- flexible data migration tool …
  - Arrow → DataFrame → plain SQL inserts → Any not supported SQL Database

- etc.

---

<div class="post-metadata">

**Author:** ![ImreSamu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/imresamu/32/20677_2.png) [@ImreSamu](https://discourse.julialang.org/u/ImreSamu)\
**Post date:** [April 18, 2021, 10:19am UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/14 "2021-04-18T10:19:20Z")

</div>

my “hacked” pg\_dump output … but this is not solve the dataframe problems.

```sql
# pg_dump -t use_cases --inserts --data-only --rows-per-insert=100 | egrep -v '^(SET|SELECT|--)' | grep .
INSERT INTO public.use_cases VALUES
	('ac7e086a-a7d5-4474-8ab4-e6b8c94994c7', 'Edited name', 'Edited description', 'Edited input', 'Edited output', 'test', 'test', 6, '3541ee59-d48e-4aaa-8f38-79554136462d', NULL, true, NULL, NULL, '2021-04-08 13:46:11.549539', 'b306ec38-ee19-4af5-9e3a-a36d2c22fe85', '2021-04-08 13:46:11.954205', 'b306ec38-ee19-4af5-9e3a-a36d2c22fe85', 'test'),
	('d1197838-17c7-43c9-80f3-91d745ac32a8', 'xyz', NULL, NULL, NULL, NULL, NULL, NULL, '71ecb06c-2555-4f2b-9b99-d1dc9c0876ca', '07b18f7a-35b6-423d-b252-daf26d6e2e1c', false, NULL, NULL, '2021-03-17 13:17:18.743356', 'f31e650c-23b7-4886-a0a1-894c5eee9443', NULL, NULL, NULL),
	('d726f6de-bd40-4c96-95c9-7bc080dab46d', '2 - with default exps', 'something else again', 'much data', '', '', '', NULL, '4e8fcfb2-4518-4445-afed-180941a0fd68', NULL, false, NULL, NULL, '2021-03-31 12:24:04.757653', '182b080b-8e42-4b85-82f5-e7e87bf8df0f', '2021-04-01 13:19:31.307656', '182b080b-8e42-4b85-82f5-e7e87bf8df0f', '');

```

for inspiration - the pg\_dump : [PostgreSQL: Documentation: 13: pg\_dump](https://www.postgresql.org/docs/13/app-pgdump.html) syntax

- prefer COPY vs INSERT - for speed reason  
_“Dump data as `INSERT` commands (rather than `COPY` ). This will make restoration very slow; it is mainly useful for making dumps that can be loaded into non-PostgreSQL databases. Any error during reloading will cause only rows that are part of the problematic `INSERT` to be lost, rather than the entire table contents. Note that the restore might fail altogether if you have rearranged column order. The `--column-inserts` option is safe against column order changes, though even slower.”_
- can customize the INSERT output; IMHO: similar will be useful
  - ` --rows-per-insert=1000`
  - `--inserts` vs `--column-inserts`

---

<div class="post-metadata">

**Author:** ![Nosferican](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nosferican/32/9275_2.png) [@Nosferican](https://discourse.julialang.org/u/Nosferican)\
**Post date:** [April 19, 2021, 4:17am UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/15 "2021-04-19T04:17:26Z")

</div>

I think pgAdmin does a lot of it already (Python based if not mistaken) as part of the GUI experience. I would welcome SQL generating code for example to create a table based on a Julia object like how R’s `RPostgresSQL` does and that could be used to add new features. Would also be nice for the postGIS domain area of creating the tables and structures for polygons and whatnot in a user friendly manner (e.g., how R’s `sf` does). For inserting, records I would try to go for something for preparing the statements.

---

<div class="post-metadata">

**Author:** ![Laco\_Kovac](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laco_kovac/32/20684_2.png) [@Laco\_Kovac](https://discourse.julialang.org/u/Laco_Kovac)\
**Post date:** [April 19, 2021, 7:18am UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/16 "2021-04-19T07:18:38Z")

</div>

Yes, the reason is similar to what ImreSamu wrote.  
We want to export certain section/portion of our data.  
We first copy required subset to temporary schema (it is about 10 tables with foreign key relationship between them), then create SQL from that, including all data there. Whole schema is then dropped, SQL text encrypted & downloaded.  
Such file can be then uploaded and imported into different server instance, under different user, etc.  
I could not use pg\_dump there, because I have only LibPQ connection to the database; I cannot call pg\_dump process there.

---

<div class="post-metadata">

**Author:** ![ImreSamu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/imresamu/32/20677_2.png) [@ImreSamu](https://discourse.julialang.org/u/ImreSamu)\
**Post date:** [April 19, 2021, 8:18am UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/17 "2021-04-19T08:18:34Z")

</div>

> [@Laco\_Kovac](#):
>
> I could not use pg\_dump there, because I have only LibPQ connection to the database; I cannot call pg\_dump process there.

IMHO:

- This should be the same connection ( user; pw; port; host ) so If you can install the `postgresql-client` package, it should work … for medium-big databases (\> 10 GB) it is better with the default COPY. ( and battle-tested ) … but at some extreme paranoid site ( ~banking ) not so easy to install any extra package/tool.
- in python there is a wrapper package for pg\_dump: [dump · PyPI](https://pypi.org/project/dump/)  
_“Wrapper around psql and pg\_dump to make it easier to backup/restore a PostgreSQL database”_  
The Julia wrapper still missing.

on the other hand,

- Julia based - text SQL target ( “insert into”, copy ) would be useful. 👍

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [April 19, 2021, 8:19am UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/18 "2021-04-19T08:19:07Z")

</div>

Maybe you can just store everything in csv (or any other table storage format) and use prepared statements to load data to new tables?

---

<div class="post-metadata">

**Author:** ![Laco\_Kovac](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laco_kovac/32/20684_2.png) [@Laco\_Kovac](https://discourse.julialang.org/u/Laco_Kovac)\
**Post date:** [April 20, 2021, 12:11pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/19 "2021-04-20T12:11:15Z")

</div>

1. Maybe I misunderstand, but I cannot find anything anywhere about julia package named “postgresql-client”.

2. Using COPY: if I use SQL as this one (example generated by pg\_dump using default options)

```julia
COPY some_ids (id, other_id) FROM stdin;
4e2aafd7-c7cc-46de-84ec-dbd8eb8b498d	99890a8b-2579-4030-bf54-0805e7f8e03a
\.

```

and I execute it, I am getting error:

```julia
ERROR: syntax error at or near "4e2"
LINE 2: 4e2aafd7-c7cc-46de-84ec-dbd8eb8b498d 99890a8b-2579-4030-bf54...
        ^
SQL state: 42601
Character: 205

```

The code as I have [here](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/2) is actually working, but may not be the most efficient.

---

<div class="post-metadata">

**Author:** ![ImreSamu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/imresamu/32/20677_2.png) [@ImreSamu](https://discourse.julialang.org/u/ImreSamu)\
**Post date:** [April 20, 2021, 1:00pm UTC](https://discourse.julialang.org/t/generating-insert-into-sql-statement/59106/20 "2021-04-20T13:00:45Z")

</div>

> [@Laco\_Kovac](#):
>
> but I cannot find anything anywhere about julia package named “postgresql-client”.

sorry; this is a Linux package.

- ` sudo apt-get install postgresql-client`

this is based on the “PostgreSQL Client Applications”

- [PostgreSQL: Documentation: 13: PostgreSQL Client Applications](https://www.postgresql.org/docs/13/reference-client.html)
  - `pg_dump` , `pg_restore` , `psql` , …

I don’t know what is the Windows package name, and probably you need to run an .exe version `pg_dump.exe`

> Using COPY: if I use SQL as this one (example generated by pg\_dump using default options)  
> and I execute it, I am getting error:

this is a **“PostgreSQL ONLY”** command → [PostgreSQL: Documentation: 13: COPY](https://www.postgresql.org/docs/13/sql-copy.html)

- so : _“There is no COPY statement in the SQL standard.”_
- important: it is **a tab separated file!** ( " tab character" )
  - be careful when copy/paste! some editor replacing with 4 space!

```julia
pg_dump -t use_cases > use_cases_backup.sql

# restore - with piping
cat use_cases_backup.sql | psql 
# restore - as a simple SQL file 
psql -f use_cases_backup.sql

```

in my backup file contains 51 “tab character”

```julia
grep -o -P '\t' use_cases_backup.sql | wc -l
51

```

if this is working via `psql` client … ( as a basic debug tools )  
and not with `LibPQ` … then need to debug … why not ?
