@@ -72,20 +72,19 @@ The same parameter name may appear multiple times in the query:
7272 ... " SELECT * FROM locations WHERE name = %(q)s OR kind = %(q)s " ,
7373 ... {" q" : " Quasar" })
7474
75- The client converts the ``%(name)s `` placeholders to positional ``? `` markers
76- before sending the query to CrateDB, so no server-side changes are required.
77-
78- .. NOTE ::
79-
80- Named parameters are not yet supported by ``executemany() ``. Use
81- positional ``? `` placeholders with a :class: `py:list ` of tuples for bulk
82- operations.
75+ The client converts the ``%(name)s `` placeholders to ``$N `` positional
76+ markers before sending the query to CrateDB.
8377
8478Bulk inserts
8579------------
8680
8781:ref: `Bulk inserts <crate-reference:http-bulk-ops >` are possible with the
88- ``executemany() `` method, which takes a :class: `py:list ` of tuples to insert:
82+ ``executemany() `` method.
83+
84+ Positional parameters
85+ .....................
86+
87+ Pass a :class: `py:list ` of sequences using ``? `` placeholders:
8988
9089 >>> cursor.executemany(
9190 ... " INSERT INTO locations (name, date, kind, position) VALUES (?, ?, ?, ?)" ,
@@ -94,10 +93,58 @@ Bulk inserts
9493 [{'rowcount': 1}, {'rowcount': 1}]
9594
9695The ``executemany() `` method returns a result :class: `dictionary <py:dict> `
97- for every tuple . This dictionary always has a ``rowcount `` key, indicating
96+ for every row . This dictionary always has a ``rowcount `` key, indicating
9897how many rows were inserted. If an error occurs, the ``rowcount `` value is
9998``-2 ``, and the dictionary may additionally have an ``error_message `` key.
10099
100+ Named parameters
101+ ................
102+
103+ ``executemany() `` also accepts a :class: `py:list ` of :class: `py:dict ` using
104+ ``%(name)s `` placeholders. The client converts both the SQL template and all
105+ rows to positional format before sending to CrateDB:
106+
107+ >>> cursor.executemany(
108+ ... " INSERT INTO locations (name, date, kind, position) "
109+ ... " VALUES (%(name)s , %(date)s , %(kind)s , %(pos)s )" ,
110+ ... [{" name" : " Cloverleaf" , " date" : " 2007-03-11" , " kind" : " Quasar" , " pos" : 7 },
111+ ... {" name" : " Old Faithful" , " date" : " 2007-03-11" , " kind" : " Quasar" , " pos" : 8 }])
112+ [{'rowcount': 1}, {'rowcount': 1}]
113+
114+ Using ``bulk_parameters `` directly
115+ ...................................
116+
117+ ``execute() `` accepts a ``bulk_parameters `` keyword argument directly:
118+
119+ .. NOTE ::
120+ Please prefer ``executemany() `` for bulk inserts, it is the standard DB-API 2.0
121+ interface. The ``bulk_parameters `` argument is a lower-level alternative.
122+
123+ >>> cursor.execute(
124+ ... " INSERT INTO locations (name, kind, position) VALUES (?, ?, ?)" ,
125+ ... bulk_parameters= [(' Cloverleaf' , ' Quasar' , 7 ),
126+ ... (' Old Faithful' , ' Quasar' , 8 )])
127+
128+ Named ``%(name)s `` placeholders are also supported. When the rows are
129+ :class: `py:dict ` objects the SQL template and rows are fully converted,
130+ identical to the ``executemany() `` path:
131+
132+ >>> cursor.execute(
133+ ... " INSERT INTO locations (name, kind, position) "
134+ ... " VALUES (%(name)s , %(kind)s , %(pos)s )" ,
135+ ... bulk_parameters= [{" name" : " Cloverleaf" , " kind" : " Quasar" , " pos" : 7 },
136+ ... {" name" : " Old Faithful" , " kind" : " Quasar" , " pos" : 8 }])
137+
138+ When the rows are already positional lists (e.g. data coming from a
139+ DataFrame), only the SQL template is rewritten. In this case the caller must
140+ ensure the value order in each row matches the placeholder order in the SQL:
141+
142+ >>> cursor.execute(
143+ ... " INSERT INTO locations (name, kind, position) "
144+ ... " VALUES (%(name)s , %(kind)s , %(pos)s )" ,
145+ ... bulk_parameters= [[' Cloverleaf' , ' Quasar' , 7 ],
146+ ... [' Old Faithful' , ' Quasar' , 8 ]])
147+
101148.. _selects :
102149
103150Selecting data
0 commit comments