Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jJkXh-00085Y-LC for psycopg@arkaria.postgresql.org; Wed, 01 Apr 2020 21:04:58 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1jJkXg-0004tf-Co for psycopg@arkaria.postgresql.org; Wed, 01 Apr 2020 21:04:56 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jJkXe-0004tK-FD for psycopg@lists.postgresql.org; Wed, 01 Apr 2020 21:04:56 +0000 Received: from [66.111.4.25] (helo=out1-smtp.messagingengine.com) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jJkXb-0000Ec-3M for psycopg@postgresql.org; Wed, 01 Apr 2020 21:04:53 +0000 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 2A93C5C0241; Wed, 1 Apr 2020 17:04:39 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Wed, 01 Apr 2020 17:04:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aklaver.com; h= subject:to:cc:references:from:message-id:date:mime-version :in-reply-to:content-type:content-transfer-encoding; s=fm2; bh=v uA4o82oVKHMxpREDpUQwkAlJhryjpjeeVPu7mNnxhQ=; b=Abmrdi3cxJFXsBWw2 1W948Ttf1ji9WW5Gz26aObnNS88iSctSVNr66573rI7quHKnlsovAHJEJ5V1GvDj WnhFtaaAQmDMsXx/i0XhHNmGjm3V0gTsW9mXFmPrV3A1lv7V5ND+IRz9tOoYiDH3 ttUGk0vu1WlsLRsBNDFfnefBF4gZpUhJhneSwKigrp9I9N1kE3mQD5ie//Au29sY eFpLlHVbz8V0e1qbENdmZmYqJxssdw5k9cN48elbS88XHZTIPxnrt/UnJa5WYN7l OGl3KE3s5KsTtMRNSz06XjwbG/mxWGi/7gXcTPy8Kfdy1nuCpGM+SgfAdKwU/BFH gd59Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm2; bh=vuA4o82oVKHMxpREDpUQwkAlJhryjpjeeVPu7mNnx hQ=; b=1QDctUhGm50wZ1/X9LqY3ESvDCiNkNVOKm+26zoQ6qdhLfylZD9MVeV9c 9mqxhfDGj8MBBecIAfH/wTH8Vtc544U2FBOQ4s6DA3g08iA1wRZyyInWQfnSBfDs R6ScF3HRr+dF62o1/tfhE3A7R3vxat4x0Vdpu0xFou6AnRXPHmCXhJfOgF+UVENZ 5w77GEfStHLEXqFhbA8/IIu7I5TvfL6jlgh+yYwJtnkw+zvnecMzkx3bVp8RKR5+ 9sej5zZW3hGlGvrm1fag8meRls+1FqEbmZUraVM2cGmSG3lXU4kXUo7hA450Nunm yeNSnAKkpsRIqltakfKMiZE5dkNbw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrtddvgdduheehucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepuffvfhfhkffffgggjggtgfesthekredttdefjeenucfhrhhomheptegurhhi rghnucfmlhgrvhgvrhcuoegrughrihgrnhdrkhhlrghvvghrsegrkhhlrghvvghrrdgtoh hmqeenucfkphepjeehrddujedvrdeltddrledvnecuvehluhhsthgvrhfuihiivgeptden ucfrrghrrghmpehmrghilhhfrhhomheprggurhhirghnrdhklhgrvhgvrhesrghklhgrvh gvrhdrtghomh X-ME-Proxy: Received: from [192.168.1.10] (75-172-90-92.tukw.qwest.net [75.172.90.92]) by mail.messagingengine.com (Postfix) with ESMTPA id 54016306CD3F; Wed, 1 Apr 2020 17:04:38 -0400 (EDT) Subject: Re: Inserting default values into execute_values To: Stephen Lagree Cc: Daniele Varrazzo , psycopg@postgresql.org References: <6db34cfa-c531-18ff-4368-bea8c171f6db@aklaver.com> <3cdc3522-f09a-529a-e329-b50418fb4172@aklaver.com> From: Adrian Klaver Message-ID: <0f255c7c-0eb0-fbfa-8c47-029f98b9a4f2@aklaver.com> Date: Wed, 1 Apr 2020 14:04:37 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.6.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit X-Host-Lookup-Failed: Reverse DNS lookup failed for 66.111.4.25 (deferred) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On 4/1/20 1:31 PM, Stephen Lagree wrote: > Thanks Daniele and Adrian, your answers were really helpful! > > Daniele, you are right, it is a waste sending long strings when I am > just trying to generate entries in the sequence. > I do want to do it in one shot so your generate_series suggestion should > be great >     insert into testins (id) select nextval('testins_id_seq') from > generate_series(1, 10); > > However, I was playing around with the sql.Default and Adrian's Default > class and couldn't get them to work with execute_values.  I know in my > case it might not make sense to use a Default literal if that is all > that is being added, but it might make sense for a query that sometimes > is used for inserting DEFAULT and sometimes to insert a value. > >             query2 = "INSERT INTO MYTABLE (id) VALUES %s RETURNING id;" >             args_list = [sql.DEFAULT, sql.DEFAULT] >             execute_values(cursor, query2, args_list, >                            template=None, page_size=100, fetch=True) > > There is a TypeError in execute_values for both Adrian's Default and > sql.Default: > >             for page in _paginate(argslist, page_size=page_size): >                 if template is None: >     >               template = b'(' + b','.join([b'%s'] * len(page[0])) > + b')' >     E               TypeError: object of type 'SQL' has no len() > >     ../../.con > da/envs/stbase/lib/python3.7/site-packages/psycopg2/extras.py:1275: > TypeError > > I added a len and slicing function to Adrian's default class and tried > it, but it then had an error with the mogrify line in execute values.  I > tried a few variations of templates with and without parentheses and > that didn't work either. The DEFAULT and sql.SQL("DEFAULT") both return objects that do not play well with the template as you found out. The simplest way I found is to do: query2 = "INSERT INTO t2 (id, name) VALUES %s RETURNING id;" execute_values(cur, query2, args_list, template="(DEFAULT, DEFAULT)", page_size=100, fetch=True) [(3,), (4,)] test=# alter table t2 alter COLUMN name set default 'name'; ALTER TABLE test=# select * from t2; id | name ----+------- 1 | test 2 | test2 (2 rows) test=# select * from t2; id | name ----+------- 1 | test 2 | test2 3 | name 4 | name (4 rows) > > -Steve > > On Wed, Apr 1, 2020 at 1:03 PM Adrian Klaver > wrote: > > On 3/31/20 7:16 PM, Daniele Varrazzo wrote: > >>> On 3/31/20 3:27 PM, Stephen Lagree wrote: > >>>> Hello, > >>>> > >>>> I am trying to insert into a table to generate sequential ids.  Is > >>>> there a way to do this repeatedly using execute_values if there is > >>>> only one column and it is auto incremented? > > > > The point of execute_values is to convert a sequence of records > into a > > VALUES thing (that's what the placeholder is for) and shoot it to the > > db in one go. I think your task is much simpler than that. > > > > In order to do what you want to do you use execute_batch and use a > > list of empty tuples for instance; > > > >      psycopg2.extras.execute_batch(cur, "insert into testins (id) > > values (default)", [() for i in range(10)]) > > > > but I think this is still silly: you are still sending a lot of > > strings from client to serve which do very little. > > > > You can easily do the same loop entirely in the database, executing a > > statement such as: > > > >      do $$ > >      declare i int; > >      begin > >          for i in select * from generate_series(1, 10) > >          loop > >              insert into testins (id) values (default); > >          end loop; > >      end > >      $$ language plpgsql; > > > > but this is still means doing n separate inserts. Even faster > would be > > just not rely on the DEFAULT literal, if you know the table you are > > inserting into or you don't mind introspecting the schema: > > > >      insert into testins (id) select nextval('testins_id_seq') from > > generate_series(1, 10); > > > > On Wed, 1 Apr 2020 at 12:08, Adrian Klaver > > wrote: > > > >>> A solution from Daniele Varrazzo.  I can't find the mailing > list post > >>> where it appeared, just where I use it in code: > > > > > > Thank you for fishing that out! But I think since the introduction of > > the 'psycopg2.sql' module the correct way to do that is to use > > something like 'sql.SQL("DEFAULT")' to compose into a query. > > Thanks, still wrapping my head around psycopg2.sql. > > A simple example: > > test=# \d t2 >                                   Table "public.t2" >   Column |       Type        | Collation | Nullable | > Default > > --------+-------------------+-----------+----------+-------------------------------- >   id     | integer           |           | not null | > nextval('t2_id_seq'::regclass) >   name   | character varying |           |          | > Indexes: >      "t2_pkey" PRIMARY KEY, btree (id) > > > import psycopg2 > from psycopg2 import sql > > con = psycopg2.connect("dbname=test host=localhost user=aklaver") > > q1 = sql.SQL("insert into t2  values > ({})").format(sql.SQL(",").join([sql.SQL("DEFAULT"), > sql.Literal('test2')])) > > print(q1.as_string(con)) > > > insert into t2  values (DEFAULT,E'test2') > > cur.execute(q1) > > test=# select * from t2; >   id | name > ----+------- >    1 | test >    2 | test2 > > > > > > Cheers, > > > > -- Daniele > > > > > -- > Adrian Klaver > adrian.klaver@aklaver.com > -- Adrian Klaver adrian.klaver@aklaver.com