Обсуждение: select where id=random()*something returns two results
======================================================================== ==== POSTGRESQL BUG REPORT TEMPLATE ======================================================================== ==== Your name : Ulrich Meis Your email address : u.meis ( at ) gmx ( dot ) de System Configuration --------------------- Architecture (example: Intel Pentium) : AMD XP 1ghz Operating System (example: Linux 2.0.26 ELF) : Linux (6month old) Gentoo PostgreSQL version (example: PostgreSQL-7.3): PostgreSQL 7.3.4 Compiler used (example: gcc 2.95.2) : gnu gcc 3.2.2 Please enter a FULL description of your problem: ------------------------------------------------ A "select * from table where primkey=..." sometimes returns two results. Having a table of quotes created as can be seen in the next section, I've seen the following in psql: select * from quotes where id=1+round(random()* cast ((select max(id) from quotes) as double precision)); id | quote | author -----+-----------------------------------------------------------+------ ----------- 187 | Vergib Deinen Feinden, aber vergiss niemals ihre Namen. | John F. Kennedy 377 | Die Wirklichkeit ist nicht so oder so, sondern so und so. | Harry Mulisch (2 rows) I'm not really into databases, but this sounds wrong. Most of the time, I actually get 0 results. This should be impossible as well, because I filled the table up without touching the serial and without deleting a single row. Please describe a way to repeat the problem. Please try to provide a concise reproducible example, if at all possible: ---------------------------------------------------------------------- create table quotes (id serial,quote text,author text); Fill in some quotes... select * from quotes where id=1+round(random()* cast ((select max(id) from quotes) as double precision)); If you know how this problem might be fixed, list the solution below: --------------------------------------------------------------------- No idea.
On Fri, 19 Sep 2003, Ulrich Meis wrote: > select * from quotes where id=1+round(random()* cast ((select max(id) > from quotes) as double precision)); > id | quote | > author > -----+-----------------------------------------------------------+------ > ----------- > 187 | Vergib Deinen Feinden, aber vergiss niemals ihre Namen. | John > F. Kennedy > 377 | Die Wirklichkeit ist nicht so oder so, sondern so und so. | Harry > Mulisch > (2 rows) > > I'm not really into databases, but this sounds wrong. Most of the time, > I actually get 0 results. The problem is that random() is evaluated on each line giving a different result. Kris Jurka
> select * from quotes where id=3D1+round(random()* cast ((select max(id) > from quotes) as double precision)); > id | quote | > author=20=20=20=20=20=20 > -----+-----------------------------------------------------------+------ > ----------- > 187 | Vergib Deinen Feinden, aber vergiss niemals ihre Namen. | John > F. Kennedy > 377 | Die Wirklichkeit ist nicht so oder so, sondern so und so. | Harry > Mulisch > (2 rows) >=20 > I'm not really into databases, but this sounds wrong. Most of the time, > I actually get 0 results. Random is calculated per call (in this case per comparison). So, the value you compare against for 187 is not the same as 377. UPDATE table SET column =3D random(); will show the effect. If you wrap randon() in a subselect, it will cause it to be evaluated once: SELECT * from quotes where id =3D 1+round((SELECT random()) * cast(....). However, a much faster query for your purposes would be: SELECT * FROM quotes ORDER BY random() LIMIT 1;
Sorry for buggering you, I get the point :) And thanks for the order by limit 1 hint. That will do. Ulrich Meis
> Sorry for buggering you, I get the point :) I think you mean 'bugging.' Buggering is something quite different.
Rod,
If the table has 100,000 tupples your query is generating 100,000 new
tupples...
Try:
select * from quotes where id = (
select int8( 1 + random() * (
select id from quotes order by id desc limit 1)));
JLL
Rod Taylor wrote:
>
> > select * from quotes where id=1+round(random()* cast ((select max(id)
> > from quotes) as double precision));
> > id | quote |
> > author
> > -----+-----------------------------------------------------------+------
> > -----------
> > 187 | Vergib Deinen Feinden, aber vergiss niemals ihre Namen. | John
> > F. Kennedy
> > 377 | Die Wirklichkeit ist nicht so oder so, sondern so und so. | Harry
> > Mulisch
> > (2 rows)
> >
> > I'm not really into databases, but this sounds wrong. Most of the time,
> > I actually get 0 results.
>
> Random is calculated per call (in this case per comparison). So, the
> value you compare against for 187 is not the same as 377.
>
> UPDATE table SET column = random(); will show the effect.
>
> If you wrap randon() in a subselect, it will cause it to be evaluated
> once:
>
> SELECT * from quotes where id = 1+round((SELECT random()) * cast(....).
>
> However, a much faster query for your purposes would be:
>
> SELECT * FROM quotes ORDER BY random() LIMIT 1;
>
> ------------------------------------------------------------------------
> Name: signature.asc
> signature.asc Type: application/pgp-signature
> Description: This is a digitally signed message part
> -----Original Message----- > From: pgsql-bugs-owner@postgresql.org [mailto:pgsql-bugs- > owner@postgresql.org] On Behalf Of Ian Grant > Sent: Friday, September 19, 2003 1:02 PM > To: Ulrich Meis > Cc: Ian.Grant@cl.cam.ac.uk; pgsql-bugs@postgresql.org > Subject: Re: [BUGS] select where id=random()*something returns two results > > > Sorry for buggering you, I get the point :) > > I think you mean 'bugging.' Buggering is something quite different. Sorry again, surely I meant bugging :-)
> -----Original Message----- > From: pgsql-bugs-owner@postgresql.org [mailto:pgsql-bugs- > owner@postgresql.org] On Behalf Of Jean-Luc Lachance > Sent: Friday, September 19, 2003 4:44 PM > To: Rod Taylor > Cc: Ulrich Meis; pgsql-bugs@postgresql.org > Subject: Re: [BUGS] select where id=random()*something returns two results > > Rod, > > If the table has 100,000 tupples your query is generating 100,000 new > tupples... > Try: > > select * from quotes where id = ( > select int8( 1 + random() * ( > select id from quotes order by id desc limit 1))); > How about select * from quotes where id=1+int8((select random())*(select max(id) from quotes)); It works, but is it more or less efficient?
On Sun, 2003-09-21 at 08:21, Ulrich Meis wrote: > > -----Original Message----- > > From: pgsql-bugs-owner@postgresql.org [mailto:pgsql-bugs- > > owner@postgresql.org] On Behalf Of Jean-Luc Lachance > > Sent: Friday, September 19, 2003 4:44 PM > > To: Rod Taylor > > Cc: Ulrich Meis; pgsql-bugs@postgresql.org > > Subject: Re: [BUGS] select where id=3Drandom()*something returns two > results > >=20 > > Rod, > >=20 > > If the table has 100,000 tupples your query is generating 100,000 new > > tupples... > > Try: > >=20 > > select * from quotes where id =3D ( > > select int8( 1 + random() * ( > > select id from quotes order by id desc limit 1))); > >=20 >=20 > How about >=20 > select * from quotes where id=3D1+int8((select random())*(select max(id) > from quotes)); >=20 > It works, but is it more or less efficient? Run EXPLAIN ANALYZE on them both and you tell me which is more efficient. Efficiency of a query tends to change with the data that it is being executed on.