zend framework get last insert id of multi row insert using execute - zend-framework

How would I get the last inserted ID using a multirow insert?
Here is my code:
$sql='INSERT INTO t (col1, col2, col3) VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9)'; // example
$stmt = $contactsTable->getAdapter()->prepare($sql);
$stmt->execute();
$rowsAdded=$stmt->rowCount(); // mysql_affected_rows
$lastId=$stmt->lastInsertId();
echo '<br>Last ID: '.$lastId;
Also, is there a method in ZF to get the next insert id before an insert?
thanks

$lastId=$contactsTable->getAdapter()->lastInsertId();
This worked.

So, here is the full working code I'm using to create a multi-row insert, getting the rows added and the last inserted id:
$contactsTable = new Contacts_Model_Contacts();
$sql='INSERT INTO t (col1, col2, col3) VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9)'; // example
$stmt = $contactsTable->getAdapter()->prepare($sql);
$stmt->execute();
$rowsAdded=$stmt->rowCount(); // mysql_affected_rows
$lastId=$contactsTable->getAdapter()->lastInsertId(); // last inserted id
echo '<br>Last ID: '.$lastId;

An alternate solution. Move off sql code from controllers and place them in models. That is what they are for.
If you are using models, you can given the name of table which has auto increment column, in class variable.
protected $_name="<table_name>";
Then in your model class method, you can get last insert id from
$insertID= $this->getAdapter()->lastInsertId();

that code should work, but it will only get you the id of your last insert.
you can get the next autoincrement with this mysql query:
SELECT Auto_increment FROM information_schema.tables WHERE TABLE_SCHEMA = 'your_db_name' AND TABLE_NAME='the_table_you_want';

Related

How to build the query "SELECT id, category IS NOT NULL AND category IN (1, 2) AS my_category FROM my_table" in knex

I'm trying to build a complex query using knex.js, where in the select part I want to select some fields as boolean if they have one of the specific values. The simplified version of the query itself is as in the title of the question like following:
SELECT
"ID",
"Category" IS NOT NULL AND "Category" IN (1, 2) AS "My_Category"
FROM "My_Table";
How could I write it in knex.js? What I have know is that:
knex.select({ID: 'My_Table.ID', My_Category: 'My_Table.Category'})
.from('My_Table);
You can use Raw Queries:
knex.raw('Select ID,Category IS NOT NULL AND Category IN (1, 2) AS My_Category from My_Table where ID = ?', [1]).then(function(resp) { ... });
Or Raw Expressions:
knex('My_Table')
.select(knex.raw('ID,Category IS NOT NULL AND Category IN (1, 2) AS My_Category'))
.where(knex.raw(1))
.orWhere(knex.raw('ID = ?', [1]))
See at:
http://knexjs.org/#Raw-Expressions
Or:
http://knexjs.org/#Raw-Queries

postgresql: "...where X IN <array type column values>" syntax?

I'm having problem with using the values of an array column in a where clause. Complete example to reproduce:
create type public.genre_type as enum ('scifi', 'fantasy', 'crime', 'horror', 'classics');
create table public.reader_profile(
id integer,
fave_genres genre_type ARRAY
);
create table public.books(
id serial not null,
title text,
genre_type public.genre_type
);
insert into public.reader_profile(id, fave_genres) values (1, array['crime', 'horror']::public.genre_type[]);
insert into public.reader_profile(id, fave_genres) values (2, array['fantasy', 'scifi']::public.genre_type[]);
insert into public.reader_profile(id, fave_genres) values (3, array['scifi', 'classics']::public.genre_type[]);
insert into public.books(title, genre_type) values ('gone with the wind', 'classics');
insert into public.books(title, genre_type) values ('Foundation', 'scifi');
insert into public.books(title, genre_type) values ('Dune', 'scifi');
-- THE FOLLOWING FAILS!!!
select * from public.books
where genre_type in (
select fave_genres from public.reader_profile where id = 2
);
I've tried ...where genre_type = ANY() per other stackoverflow answers as well as ...where genre_type <# () and I can't get anything to work! It seems the inner query (which works) is being return as an array type and not a list of values or something. Any help appreciated!!
I agree with #Hogan that this seems doable with a JOIN but the syntax you are looking for is the following:
SELECT *
FROM books
WHERE genre_type = ANY(ARRAY(SELECT fave_genres FROM reader_profile WHERE id = 2))
;
Demo
Can I suggest using a join instead?
select *
from public.books b
join public.reader_profile fg on b.genre_type = ANY(rp.fave_genres) and fg.id = 2

Having trouble with psql \copy command

I'm a postrgresql noob. I'm using psql on a remote server. I've made a query that I'd like to download as a csv. The query runs just fine on its own.
There are two tables involved in the query. The first:
CREATE TABLE players (username varchar(100), skill varchar(100),id int);
INSERT INTO players VALUES
('user1', 'flight', 1),
('user2', 'run', 2),
('user3', 'run', 3),
('user4', 'flight', 4),
('user5', 'flight', 5),
('user6', 'climb', 6),
('user7', 'flight', 7),
('user8', 'flight', 8),
('user9', 'flight', 9),
('user10', 'climb', 10);
The second table is temporary, I only need it to exist to extract this csv:
CREATE TEMP TABLE specific_players (username varchar(100));
INSERT INTO specific_players VALUES
('user2'),
('user5'),
('user7'),
('user9');
my query looks like this:
select * from players p inner join specific_players sp USING (username);
Like I said, that works just fine.
But when I try to wrap it in a copy command
\copy (select * from players inner join specific_players USING (username)) to '/Users/me/path/to/folder/filename.csv' with csv
I get an error:
ERROR: syntax error at or near "("
LINE 1: COPY ( select * from players p join specific_playe...
The file IS created on my computer, but it's empty. Any idea what I'm doing wrong?

How can I filter RETURNING *?

I have the following scenario. I have a table that has an IsDeleted flag I set for doing a 'soft delete' of records. I am doing an UPSERT where I am adding, modifying and flagging as deleted some records. I want to exclude records that have been flagged as deleted from the RETURNING statement. I have attempted to just append WHERE tbltest_IsDeleted = 0 to the end of the following SQL but it gives me the error: ERROR: syntax error at or near "WHERE"
How can I filter the results of the RETURNING * in the following statement?
INSERT INTO tbltest (
tbltest_ID,
tbltest_Name,
tbltest_Description,
tbltest_IsDeleted)
VALUES
(DEFAULT, 'new record','new record description', 0),
(4, 'modified record name','modified record description', 0),
(5, 'existing record name','existing record description', 1)
ON CONFLICT (tbltest_ID) DO UPDATE SET (
tbltest_Name,
tbltest_Description,
tbltest_IsDeleted) = (
excluded.tbltest_Name,
excluded.tbltest_Description,
excluded.tbltest_IsDeleted) RETURNING *;
Worked it out, here is how I was able to do it:
WITH rows AS (
INSERT INTO tbltest (
tbltest_ID,
tbltest_Name,
tbltest_Description,
tbltest_IsDeleted)
VALUES
(DEFAULT, 'new record','new record description', 0),
(4, 'modified record name','modified record description', 0),
(5, 'existing record name','existing record description', 1)
ON CONFLICT (tbltest_ID) DO UPDATE SET (
tbltest_Name,
tbltest_Description,
tbltest_IsDeleted) = (
excluded.tbltest_Name,
excluded.tbltest_Description,
excluded.tbltest_IsDeleted) RETURNING *
)
SELECT * FROM rows WHERE rows.tbltest_IsDeleted = 0
Hopefully this saves someone some time ;-)

How to refer OLD.X at ON CONFLICT DO UPDATE SET X = OLD.X + EXCLUDED.X

There are an alias for "old value" in the ON CONFLICT DO UPDATE?
My real life problem is
INSERT INTO art.validterm (namespace,term,X,info)
SELECT namespace,term,array_agg(Xi), 'etc'
FROM term_raw_Xs
GROUP BY namespace,term
ON CONFLICT (term) DO
UPDATE SET aliases=OLD.X||EXCLUDED.X
WHERE term=EXCLUDED.term
PS: no "OLD" exists, is the question. The parser say that only X is ambigous.
Simply replacing OLD with the name of the table, in your case: validterm, worked for me.
My test:
DROP TABLE IF EXISTS work.term_raw;
CREATE TABLE work.term_raw
(
unique_field INT UNIQUE,
x_field TEXT
);
INSERT INTO work.term_raw VALUES (1, 'A');
INSERT INTO work.term_raw VALUES (1, 'B')
ON CONFLICT (unique_field) DO UPDATE SET x_field = term_raw.x_field || EXCLUDED.x_field;
SELECT * FROM work.term_raw;
My result: