Change from 9.6 to 11?

2018-12-20 Thread Chuck Martin
I hope someone here can see something that eludes me. I've recently moved a
database from PostgreSQL 9.6 to 11, and there are a few oddities. The
following select statement returns zero rows when it should return one.
This is one of a small number of records that exist, but are not returned
by the query. When I include the main table, event, and any one of the
associated tables, the record is returned, but no record is returned with
the entire statement. All the primary keys (_pkey) and foreign keys (_fkey)
are integers. The field I suspect as the possible culprit, event.InsBy, is
a character column I'm converting to do a lookup on a primary key
(integer): event.InsBy::int = usr.Usr_pkey. Maybe PG 11 doesn't recognize
the same syntax for cast as PG 9.6? Or maybe I'm overlooking something else
basic. Thanks for reading!

SELECT
event.Event_pkey,ombcase.CaseName,status.StatusID,eventtype.EventTypeID,event.datetime
AT TIME ZONE 'US/Eastern',event.endtime AT TIME ZONE
'US/Eastern',event.EventDeadline,eventtype.EventIsDeadline,eventtype.OnCalendar,event.EventConfirmed,event.Description,event.PrivateNote,primaryresp.PrimaryrespID,event.IsPrivate,event.Hours,event.EventDone,event.EventDoneDate,event.Importance,event.Urgency,event.InCourt,event.LeadTime,doc.DocID,doctype.DocTypeID,project.ProjectName,usr.UserID,eventtype.Hours,event.Active,event.EditNum,event.InsBy,event.InsDateTime,event.ModBy,event.ModDateTime,event.Case_fkey,event.Eventtype_fkey,event.Project_fkey,event.Doc_fkey,event.Primaryresp_fkey,project.Project_pkey,primaryresp.PrimaryrespHolidayGroup,primaryresp.Usr_pkey,backup.Usr_pkey,doctype.Doctype_pkey,primaryresp.Primaryrespbackup_fkey,ombcase.Status_fkey,event.Parentevent_fkey,event.EventPostRemand
FROM
event,ombcase,status,eventtype,primaryresp,doc,doctype,project,usr,backup
WHERE event.Case_fkey = Case_pkey
AND event.Eventtype_fkey = Eventtype_pkey
AND event.Project_fkey = Project_pkey
AND event.Primaryresp_fkey = primaryresp.Usr_pkey
AND event.Doc_fkey = Doc_pkey
AND Doctype_fkey = Doctype_pkey
AND usr.Backup_fkey = backup.Usr_pkey
AND ombcase.Status_fkey = status.Status_pkey
AND event.InsBy::int = usr.Usr_pkey
AND event.Event_pkey = 1060071
ORDER BY EventDone, DateTime DESC

Chuck Martin
Avondale Software


Re: Change from 9.6 to 11?

2018-12-21 Thread Chuck Martin
On Thu, Dec 20, 2018 at 10:12 PM Adrian Klaver 
wrote:

> On 12/20/18 5:51 PM, Chuck Martin wrote:
>
> Please reply to list also.
> Ccing list.
>
> >
> >
> > On Thu, Dec 20, 2018 at 7:56 PM Adrian Klaver  > <mailto:adrian.kla...@aklaver.com>> wrote:
> >
> > On 12/20/18 12:35 PM, Chuck Martin wrote:
> >  > I hope someone here can see something that eludes me. I've
> recently
> >  > moved a database from PostgreSQL 9.6 to 11, and there are a few
> >  > oddities. The following select statement returns zero rows when it
> >  > should return one. This is one of a small number of records that
> > exist,
> >  > but are not returned by the query. When I include the main table,
> > event,
> >  > and any one of the associated tables, the record is returned, but
> no
> >  > record is returned with the entire statement. All the primary keys
> >  > (_pkey) and foreign keys (_fkey) are integers. The field I
> > suspect as
> >  > the possible culprit, event.InsBy, is a character column I'm
> > converting
> >  > to do a lookup on a primary key (integer): event.InsBy::int =
> >  > usr.Usr_pkey. Maybe PG 11 doesn't recognize the same syntax for
> > cast as
> >  > PG 9.6? Or maybe I'm overlooking something else basic. Thanks for
> > reading!
> >
> > So if in the WHERE you leave out the:
> >
> > AND event.InsBy::int = usr.Usr_pkey
> >
> > and in the SELECT you add:
> >
> > event.InsBy, event.InsBy::int AS InsByInt
> >
> > what do you see?
> >
> >
> > I get 91 copies of the record. One for each record in the usr table.
>
> But do the event.InsBy, event.InsBy::int AS InsByInt values match each
> other?
>
> Just had a thought, what if you join just the event and usr tables on:
>
> event.InsBy::int = usr.Usr_pkey
>
> Trying to determine whether your suspected culprit really is the culprit.


Thanks, Adrian. This led me to the problem. The data in InsBy was invalid.
That is to say, a join wasn’t possible because no record exists with that
primary key. Not sure how that occurred, but now I know why. Had I
anticipated this might happen, I would have used an outer join.

I appreciate your help solving this minor, but annoying, issue.

>
>
>
> --
> Adrian Klaver
> adrian.kla...@aklaver.com
>
> --
Chuck Martin
Avondale Software


getting pg_basebackup to use remote destination

2018-12-29 Thread Chuck Martin
I thought I knew how to do this, but I apparently don't. I have to set up a
new server as a standby for a PG 11.1 server. The main server has a lot
more resources than the standby. What I want to do is run pg_basebackup on
the main server with the output going to the data directory on the new
server. But when I give this command:

pg_basebackup -D "ssh root@10.0.1.16:/mnt/dbraid/data" -P -v -X s


it instead writes to my root drive which doesn't have the space, so it
fails and deletes the partial backup.


While I think I could figure out how to backup to a local directory then
rsync it to the new server, I'd like to avoid that due to the 750GB size.


Is there a way to tell pg_basebackup to use a remote destination for
output? Or do I have to run pg_basebackup on the standby server?


And while I'm asking, has anyone yet written a guide/tutorial for PG 11
replication? Everything I find online is very old.

Chuck Martin
Avondale Software


Re: getting pg_basebackup to use remote destination

2018-12-30 Thread Chuck Martin
On Sun, Dec 30, 2018 at 11:20 AM Peter Eisentraut <
peter.eisentr...@2ndquadrant.com> wrote:

> On 29/12/2018 20:04, Chuck Martin wrote:
> > I thought I knew how to do this, but I apparently don't. I have to set
> > up a new server as a standby for a PG 11.1 server. The main server has a
> > lot more resources than the standby. What I want to do is run
> > pg_basebackup on the main server with the output going to the data
> > directory on the new server. But when I give this command:
> >
> > pg_basebackup -D "ssh root@10.0.1.16:/mnt/dbraid/data" -P -v -X s
> >
> >
> > it instead writes to my root drive which doesn't have the space, so it
> > fails and deletes the partial backup.
>
> What you might be thinking of is the "old" method of doing base backups
> before pg_basebackup:  Call pg_start_backup() and then do file system
> operations (tar, scp, whatever) to move the data files to where you want
> them.  This is mostly obsolete.  You should run pg_basebackup on the
> host where you want to set up your standby


Thanks. It’s been a while since I set up replication. Not to mention
several Postgres versions. I’ve started pg_basebackup from the standby. It
failed once due to an ssh error, but I reloaded sshd and started again. May
take a while. It about 750gb.

> .
>
> --
> Peter Eisentraut  http://www.2ndQuadrant.com/
> PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>
> --
Chuck Martin
Avondale Software


Re: getting pg_basebackup to use remote destination

2018-12-30 Thread Chuck Martin
Maybe I need to rethink ths and take Jeff's advice. I executed this:

pg_basebackup -h [main server's URL] -U postgres -P -v -X s -D
/mnt/dbraid/data

8 hours ago, and it is now still at 1%. Should it be that slow? The
database in question is about 750 GB, and both servers are on the same GB
ethernet network.

Chuck Martin
Avondale Software


On Sun, Dec 30, 2018 at 3:28 PM Jeff Janes  wrote:

> On Sat, Dec 29, 2018 at 2:05 PM Chuck Martin 
> wrote:
>
>> I thought I knew how to do this, but I apparently don't. I have to set up
>> a new server as a standby for a PG 11.1 server. The main server has a lot
>> more resources than the standby. What I want to do is run pg_basebackup on
>> the main server with the output going to the data directory on the new
>> server.
>>
>
> pg_basebackup consumes few resources on the standby anyway in the mode you
> are running it, other than network and disk.  And those are inevitable
> given your end goal, so if you could do what you want, I think it still
> wouldn't do what you want.
>
> If you really want to spare the network, you can run compression on the
> server side then decompress on the standby.  Currently you can't compress
> on the server when invoking it on the standby, so:
>
> pg_basebackup -D - -Ft -X none |pxz | ssh 10.0.1.16 "tar -xJf - -C
> /somewhere/data_test"
>
> Unfortunately you can't use this along with -X stream or -X fetch.
>
> Really I would probably compress to a file and then use scp/rsync, rather
> the streaming into ssh.  That way if ssh gets interrupted, you don't lose
> all the work.
>
> Cheers,
>
> Jeff
>
>>


Re: getting pg_basebackup to use remote destination

2018-12-31 Thread Chuck Martin
On Mon, Dec 31, 2018 at 12:05 PM Jeff Janes  wrote:

> On Sun, Dec 30, 2018 at 6:17 PM Chuck Martin 
> wrote:
>
>> Maybe I need to rethink ths and take Jeff's advice. I executed this:
>>
>> pg_basebackup -h [main server's URL] -U postgres -P -v -X s -D
>> /mnt/dbraid/data
>>
>> 8 hours ago, and it is now still at 1%. Should it be that slow? The
>> database in question is about 750 GB, and both servers are on the same GB
>> ethernet network.
>>
>
> Over gigabit ethernet, it should not be that slow.  Unless the network is
> saturated with other traffic or something.  Might be time to call in the
> network engineers.  Can you transfer static files at high speeds between
> those two hosts using scp or rsync?  (Or use some other technique to take
> PostgreSQL out of the loop and see if your network is performing as it
> should)
>
> Are you seeing transfers at a constant slow rate, or are their long
> freezes or something?  Maybe the initial checkpoint was extremely slow?
> Unfortunately -P option (even with -v) doesn't make this easy to figure
> out.  So alas it's back to old school stopwatch and a pen and paper (or
> spreadsheet).
>
> Cheers,
>
> Jeff
>
Using iperf, the transfer speed between the two servers (from the main to
the standby) was 938 Mbits/sec. If I understand the units correctly, it is
close to what it can be.

Your earlier suggestion was to do the pg_basebackup locally and rsync it
over. Maybe that would be faster. At this point, it is saying it is 6%
through, over 24 hours after being started.

Chuck Martin
Avondale Software


Query help

2019-01-01 Thread Chuck Martin
Sorry if this is too basic a question for this list, but I don't fully get
how to use aggregates (sum()) and group-by together. I'm trying to get a
list of transactions where the total for a given account exceeds a given
number. I'm not sure an example is needed, but if so, consider this
simplified data:

accountid.   name
1  bill
2. james
3  sarah
4  carl

transaction
id. amount.  accountid. name
1.  50.  1   bill
2.  25.  2   james
3   35   4   carl
4.  75.  1   bill
5   25.  1   bill
6   50   3   sarah

results wanted-all transactions where account total >= 50

id. amount.  accountid.name
1.  50.  1   bill
3.  75.  1   bill
4   25.  1   bill
5   50   3   sarah

I've tried to understand how to use GROUP BY and HAVING, but the penny
won't drop. I keep getting errors saying that all columns in the SELECT
have to also be in the GROUP BY, but nothing I've done seems to produce the
correct results. I think because the GROUP BY contains multiple columns, so
each row is treated as a group. It also is difficult to parse out since in
the real world, many more tables and columns are involved.

Chuck Martin
Avondale Software


Re: getting pg_basebackup to use remote destination

2019-01-03 Thread Chuck Martin
On Thu, Jan 3, 2019 at 3:46 PM Stephen Frost  wrote:

> Greetings Chuck,
>
> * Chuck Martin (clmar...@theombudsman.com) wrote:
> > Using iperf, the transfer speed between the two servers (from the main to
> > the standby) was 938 Mbits/sec. If I understand the units correctly, it
> is
> > close to what it can be.
>
> That does look like the rate it should be going at, but it should only
> take about 2 hours to copy 750GB at that rate.


That’s what I was expecting.

>
> How much WAL does this system generate though...?  If you're generating
> a very large amount then it's possible the WAL streaming is actually
> clogging up the network and causing the rate of copy on the data files
> to be quite slow.  You'd have to be generating quite a bit of WAL
> though.


It shouldn’t be excessive, but I’ll look closely at that.

>
>
> > Your earlier suggestion was to do the pg_basebackup locally and rsync it
> > over. Maybe that would be faster. At this point, it is saying it is 6%
> > through, over 24 hours after being started.
>
> For building out a replica, I'd tend to use my backups anyway instead of
> using pg_basebackup.  Provided you have good backups and reasonable WAL
> retention, restoring a backup and then letting it replay WAL from the
> archive until it can catch up with the primary works very well.  If you
> have a very high rate of WAL then you might consider taking a full
> backup and then taking an incremental backup (which is much faster, and
> reduces the amount of WAL required to be only that needed for the length
> of time that the incremental backup is started until the replica has
> caught up to WAL that the primary has).
>
> There's a few different backup tools out there which can do parallel
> backup and in-transit compression, which loads up the primary's CPUs
> with process doing compression but should reduce the overall time if the
> bottleneck is the network.


I’ll check out some solutions this weekend.

I appreciate the tips.

Chuck

>
>
> Thanks!
>
> Stephen
>
-- 
Chuck Martin
Avondale Software


Query help

2019-01-26 Thread Chuck Martin
I'm having trouble formulating a query. This is a simplified version of the
tables:

ombcase

case_pkey integer, primary key
casename varchar
insdatetime timestamp w/o time zone
status_fkey integer, foreign key

status

status_pkey integer, primary key
statusid varchar

statuschange

statuschange_pkey integer, primary key
insdatetime timestamp w/o time zone
ombcase_fkey integer, foreign key
oldstatus_fkey integer, foreign key
newstatus_fkey integer, foreign key
active integer, not nullable

The idea should be obvious, but to explain, insdatetime is set when a new
record is created in any table. All records in ombcase have a foreign key
to status that can't be null. When status changes, a record is created in
statuschange recording the old and new status keys, and the time (etc).

The goal is to find records in ombcase that have not had a status change in
xx days. If the status has not changed, there will be no statuschange
record.

This query returns the age of each ombcase and the last statuschange
record, but only if there is a statuschange record:

--Finds the age and last status change for open cases, but not age of cases
with no status change

SELECT   casename, age(ombcase.insdatetime) AS caseage,
age(laststatuschange.created_at) AS statusage

FROM

(SELECT

case_fkey, MAX(insdatetime) AS created_at

FROM

statuschange

GROUP BY

case_fkey) AS laststatuschange

INNER JOIN

ombcase

ON

laststatuschange.case_fkey = case_pkey

RIGHT JOIN status

ON status_fkey = status_pkey

WHERE lower(statusid) NOT LIKE ('closed%')

AND case_pkey <> 0


I want to use coalesce
(age(ombcase.insdatetime),age(statuschange.insdatetime) ) to return the
time that a case has been in a status—or without a status change. But first
I have to find the cases with no statuschange record. I was able to do
that, too, using this query:


--find cases in status too long

SELECT  casename, coalesce
(age(ombcase.insdatetime),age(statuschange.insdatetime) )

FROM ombcase

LEFT JOIN statuschange

ON case_fkey = case_pkey

LEFT JOIN status

ON status_fkey = status_pkey

AND lower(statusid) NOT LIKE ('closed%')

AND coalesce ( age(ombcase.insdatetime), age(statuschange.insdatetime) ) >
'2 months'


But this query will return all statuschange records for an ombcase record
that has multiple ones.


Any suggestions on how to combine the two ideas?

Chuck Martin
Avondale Software
-- 
Chuck Martin
Avondale Software


Re: Query help

2019-01-27 Thread Chuck Martin
Chuck Martin
Avondale Software


On Sun, Jan 27, 2019 at 2:55 PM Adrian Klaver 
wrote:

> On 1/26/19 3:04 PM, Chuck Martin wrote:
> [snip]
> Outline form:
>
> 1) If a record is in ombcase it has a status('in a status') by definition.
>
>  From query below you are not looking for just records in ombcase, but
> those that have a statusid other then 'closed%' in status table.
>
> 2) For the criteria in 1) you want to find the age of the last
> statuschange.
>
> To me that leads to something like:
>
> SELECT
> case_pkey
> FROM
> ombcase AS
> JOIN
> status
> ON
> ombcase.case_pkey = status.status_fkey
> LEFT JOIN
> statuschange
> ON  -- Or statuschange.ombcase_fkey. Not clear from above.
> statuschange.case_fkey = ombcase.status_pkey
> GROUP BY
> ombcase.pkey
> HAVING
> status.LOWER(statusid) NOT LIKE ('closed%')
> AND
> max(coalesce(statuschange.insdatetime, ombcase.insdatetime))
> < 'some date'
>
> Obviously not tested.
>

Thanks, Adrian. This got me a lot closer, but I'm puzzled by the number of
records returned. There are 3120 ombcase records with a statusid that is <>
'closed%':

SELECT count(ombcase.case_pkey)

FROM ombcase,status

WHERE ombcase.status_fkey = status.status_pkey  AND lower(status.statusid)
NOT LIKE  ('closed%')


But 3378 are returned by:

SELECT  ombcase.case_pkey, ombcase.casename,
COALESCE(AGE(statuschange.insdatetime), AGE(ombcase.insdatetime)) AS
age_in_status

FROM ombcase

INNER JOIN status

ON ombcase.status_fkey = status.status_pkey

LEFT JOIN statuschange

ON statuschange.case_fkey = ombcase.case_pkey

GROUP BY ombcase.case_pkey, status.statusid, statuschange.insdatetime,
ombcase.insdatetime

HAVING LOWER(status.statusid) NOT LIKE ('closed%')

AND ombcase.case_pkey <> 0

AND MAX(COALESCE(AGE(statuschange.insdatetime), AGE(ombcase.insdatetime)))
> '2 months'
ORDER BY age_in_status DESC

I don't know where the extra 258 records came from, and I think I need to
keep working on it until the query returns 3120 records.


Re: Query help

2019-01-27 Thread Chuck Martin
On Sun, Jan 27, 2019 at 8:07 AM Peter J. Holzer  wrote:

> On 2019-01-26 18:04:23 -0500, Chuck Martin wrote:
> [snip]
> > The idea should be obvious, but to explain, insdatetime is set when a new
> > record is created in any table. All records in ombcase have a foreign
> key to
> > status that can't be null. When status changes, a record is created in
> > statuschange recording the old and new status keys, and the time (etc).
> >
> > The goal is to find records in ombcase that have not had a status change
> in xx
> > days. If the status has not changed, there will be no statuschange
> record.
>
> The easiest way is to use set operations:
>
> select case_pkey from ombcase;
> gives you all the ombcase ids.
>
> select ombcase_fkey from statuschange where insdatetime >= now()::date -
> xx;
> gives you all ombcase ids which had a status change in the last xx days.
>
> Therefore,
> select case_pkey from ombcase
> except
> select ombcase_fkey from statuschange where insdatetime >= now()::date -
> xx;
> gives you all ombcase ids which did /not/ have a status change in the
> last xx days.
>

I was not familiar with set operations, but studied up a bit and thought I
was getting there. Not quite, though. I have two queries that individually
return 1) all ombcase records with no statuschange record, and 2) the
newest statuschange record for each case that has a statuschange record.
But just putting UNION between then doesn't work. Here are my queries:

--First, find all open cases with no statuschange record
SELECT

case_pkey,statuschange_pkey,case_fkey,ombcase.insdatetime,statuschange.insdatetime
FROM
ombcase
LEFT JOIN
statuschange
ON
  statuschange.case_fkey = case_pkey
  AND case_pkey <> 0
LEFT JOIN
status
 ON status_fkey = status_pkey
  WHERE lower(statusid) NOT LIKE  ('closed%')
  AND statuschange.statuschange_pkey IS NULL
UNION
  --Now find the last status change record for each case that has one
  SELECT DISTINCT ON (case_fkey)

case_pkey,statuschange_pkey,case_fkey,ombcase.insdatetime,statuschange.insdatetime
FROM
statuschange,ombcase,status
WHERE case_fkey = case_pkey
AND status_fkey = status_pkey
AND LOWER(statusid) NOT LIKE ('closed%')
ORDER BY case_fkey, statuschange.insdatetime DESC

If I run each part separately, I get the expected number of records.
When I combine them with UNION, I get "missing FROM-clause entry for
table "statuschange"
So I'm very close here, and these two return the exact number of
records I'm expecting. So I just need to get them added together. Then
I expect I can put the whole thing in a WHERE clause with "AND
ombcase.case_pkey IN ([the combined results])"


>
> Another way would be to use a CTE
> (https://www.postgresql.org/docs/10/queries-with.html) to extract the
> last status change for each ombcase and then do a left join of ombcase
> to that CTE.
>
> hp
>
>
> --
>_  | Peter J. Holzer| we build much bigger, better disasters now
> |_|_) || because we have much more sophisticated
> | |   | h...@hjp.at | management tools.
> __/   | http://www.hjp.at/ | -- Ross Anderson <https://www.edge.org/>
>


Re: Query help

2019-01-27 Thread Chuck Martin
On Sun, Jan 27, 2019 at 5:27 PM Chuck Martin 
wrote:

> On Sun, Jan 27, 2019 at 8:07 AM Peter J. Holzer  wrote:
>
>> On 2019-01-26 18:04:23 -0500, Chuck Martin wrote:
>> [snip]
>> > The idea should be obvious, but to explain, insdatetime is set when a
>> new
>> > record is created in any table. All records in ombcase have a foreign
>> key to
>> > status that can't be null. When status changes, a record is created in
>> > statuschange recording the old and new status keys, and the time (etc).
>> >
>> > The goal is to find records in ombcase that have not had a status
>> change in xx
>> > days. If the status has not changed, there will be no statuschange
>> record.
>>
>> The easiest way is to use set operations:
>>
>> select case_pkey from ombcase;
>> gives you all the ombcase ids.
>>
>> select ombcase_fkey from statuschange where insdatetime >= now()::date -
>> xx;
>> gives you all ombcase ids which had a status change in the last xx days.
>>
>> Therefore,
>> select case_pkey from ombcase
>> except
>> select ombcase_fkey from statuschange where insdatetime >= now()::date -
>> xx;
>> gives you all ombcase ids which did /not/ have a status change in the
>> last xx days.
>>
>
> I was not familiar with set operations, but studied up a bit and thought I
> was getting there. Not quite, though. I have two queries that individually
> return 1) all ombcase records with no statuschange record, and 2) the
> newest statuschange record for each case that has a statuschange record.
> But just putting UNION between then doesn't work. Here are my queries:
>
> --First, find all open cases with no statuschange record
> SELECT
>
> case_pkey,statuschange_pkey,case_fkey,ombcase.insdatetime,statuschange.insdatetime
> FROM
> ombcase
> LEFT JOIN
> statuschange
> ON
>   statuschange.case_fkey = case_pkey
>   AND case_pkey <> 0
> LEFT JOIN
> status
>  ON status_fkey = status_pkey
>   WHERE lower(statusid) NOT LIKE  ('closed%')
>   AND statuschange.statuschange_pkey IS NULL
> UNION
>   --Now find the last status change record for each case that has one
>   SELECT DISTINCT ON (case_fkey)
>
> case_pkey,statuschange_pkey,case_fkey,ombcase.insdatetime,statuschange.insdatetime
> FROM
> statuschange,ombcase,status
> WHERE case_fkey = case_pkey
> AND status_fkey = status_pkey
> AND LOWER(statusid) NOT LIKE ('closed%')
> ORDER BY case_fkey, statuschange.insdatetime DESC
>
> If I run each part separately, I get the expected number of records. When I 
> combine them with UNION, I get "missing FROM-clause entry for table 
> "statuschange"
> So I'm very close here, and these two return the exact number of records I'm 
> expecting. So I just need to get them added together. Then I expect I can put 
> the whole thing in a WHERE clause with "AND ombcase.case_pkey IN ([the 
> combined results])"
>
> This was pretty easy to resolve. Putting parentheses around each half of
the query caused it to return the right results. Then I could reduce the
columns to just ombcase.case_pkey and use an IN statement. I think this
gets me where I need to be. I appreciate the help!

Chuck


HAVING query structured wrong

2019-02-18 Thread Chuck Martin
I am trying to create a query that returns all transactions for each person
who has a balance over a given amount. I thought HAVING was the answer, but
if so, I'm mis-using it. This query returns only transactions exceeding the
given amount rather than transactions for people whose balance is over the
amount:

SELECT
fullname,contactnameaddress.streetaddress,contactnameaddress.towncityname,
contactnameaddress.stateprovabbrev,contactnameaddress.postalcode,
transdate,linkednameid,transreference,
transamount,caseid,transcheckno,lastorcompanyname,firstname
FROM trans,ombcase,client,contactnameaddress,linkedname,status
WHERE transistrust <> 1
AND client_fkey = client_pkey
AND case_fkey = case_pkey
AND clientname_fkey = contactnameaddress.contactname_pkey
AND linkedname_fkey = linkedname.contactname_pkey
AND status_fkey = status_pkey
AND lower(statusid) NOT LIKE ('closed%')
AND transcleared <> 1
GROUP BY case_pkey,contactnameaddress.streetaddress,
contactnameaddress.towncityname,
contactnameaddress.stateprovabbrev,
contactnameaddress.postalcode,
transdate,transreference,transamount,
fullname,linkednameid,
contactnameaddress.lastorcompanyname,
contactnameaddress.firstname,caseid,
transcheckno
HAVING sum(transamount)>= 50

Since that returned the wrong set of records, I created another that
returns the correct set of people with balances over the given amount. But
I can't figure out how to use this to get all the transactions for people
returned by this query:

SELECT case_pkey
FROM trans,ombcase,status
WHERE case_fkey = case_pkey
AND status_fkey = status_pkey
AND statusopen = 1
AND transistrust <> 1
AND transcleared <> 1
GROUP BY case_pkey
HAVING sum(transamount) >= 50

ORDER BY case_pkey

So how do I get all transactions for each case_pkey? I've read the
documentation on WITH clauses (CTEs), but that just left my head spinning.

Chuck Martin
Avondale Software


Re: HAVING query structured wrong

2019-02-19 Thread Chuck Martin
On Mon, Feb 18, 2019 at 12:37 PM Andrew Gierth 
wrote:

> >>>>> "Chuck" == Chuck Martin  writes:
>
>  Chuck> I am trying to create a query that returns all transactions for
>  Chuck> each person who has a balance over a given amount. I thought
>  Chuck> HAVING was the answer, but if so, I'm mis-using it. This query
>  Chuck> returns only transactions exceeding the given amount rather than
>  Chuck> transactions for people whose balance is over the amount:
>  [snip]
>  Chuck> Since that returned the wrong set of records, I created another
>  Chuck> that returns the correct set of people with balances over the
>  Chuck> given amount. But I can't figure out how to use this to get all
>  Chuck> the transactions for people returned by this query:
>
>  Chuck> SELECT case_pkey
>  Chuck> FROM trans,ombcase,status
>  Chuck> WHERE case_fkey = case_pkey
>  Chuck> AND status_fkey = status_pkey
>  Chuck> AND statusopen = 1
>  Chuck> AND transistrust <> 1
>  Chuck> AND transcleared <> 1
>  Chuck> GROUP BY case_pkey
>  Chuck> HAVING sum(transamount) >= 50
>
>  Chuck> ORDER BY case_pkey
>
>  Chuck> So how do I get all transactions for each case_pkey?
>
> You can join the result of any subquery as if it were a table, either
> with or without using a CTE:
>
> SELECT ...
>   FROM (select case_pkey from ... having ...) AS cases,
>trans
>  WHERE trans.case_fkey = cases.case_pkey;


>
> (incidentally, please qualify all the column references in your query
> with a table name or alias, otherwise people reading your code have no
> idea which column is supposed to be in which table)


Sorry. That was sloppy.

But working with this idea, I got the query working, so I appreciate the
pointer. For anyone wanting to see how I did so, here is the working query
(replacing the variable for the minimum balance to include with "50"):

-- Find transactions for client invoices using subquery to find client total
SELECT
contactnameaddress.fullname,contactnameaddress.streetaddress,contactnameaddress.towncityname,
contactnameaddress.stateprovabbrev,contactnameaddress.postalcode,
trans.transdate,linkedname.linkednameid,trans.transreference,
trans.transamount,ombcase.caseid,trans.transcheckno,contactnameaddress.lastorcompanyname,contactnameaddress.firstname
FROM trans,ombcase,client,contactnameaddress,linkedname,status ,
 (SELECT case_pkey FROM  ombcase,trans , status
WHERE trans.case_fkey = ombcase.case_pkey
AND ombcase.status_fkey = status_pkey
AND status.statusopen = 1
AND trans.transistrust <> 1
AND trans.transcleared <> 1
GROUP BY ombcase.case_pkey
HAVING sum(trans.transamount) >= 50) AS cases
WHERE trans.case_fkey = cases.case_pkey
AND trans.transistrust <> 1
AND ombcase.client_fkey = client.client_pkey
AND client.clientname_fkey = contactnameaddress.contactname_pkey
AND trans.linkedname_fkey = linkedname.contactname_pkey
AND ombcase.status_fkey = status.status_pkey
AND status.statusopen = 1
AND trans.transcleared <> 1
AND trans.Case_fkey = ombcase.case_pkey
GROUP BY ombcase.case_pkey,contactnameaddress.streetaddress,
contactnameaddress.towncityname, contactnameaddress.stateprovabbrev,
contactnameaddress.postalcode,
trans.transdate,trans.transreference,trans.transamount,
contactnameaddress.fullname,linkedname.linkednameid,
contactnameaddress.lastorcompanyname,
contactnameaddress.firstname,ombcase.caseid,
trans.transcheckno

I'll try to learn the other methods using your examples. Again, I
appreciate the help.

or with a CTE,
>
> WITH cases AS (select ... from ... having ...)
> SELECT ...
>   FROM cases, trans
>  WHERE trans.case_fkey = cases.case_pkey;
>
> There's also a third method with window functions instead of GROUP BY,
> which is to do something like
>
> SELECT ...
>   FROM (select ...,
>sum(transamount) over (partition by case_pkey) as total_amt
>   from ...) s
>  WHERE total_amt > 50;
>
> --
> Andrew (irc:RhodiumToad)
>
>


Re: Where to store Blobs?

2019-03-13 Thread Chuck Martin
I store them as bytea in the database despite the fact that there are
benefits to storing them in the file system. The reason is that it is
easier to secure access to the database than to secure both the database
and provide secure access to the file system.

Chuck Martin
Avondale Software


On Wed, Mar 13, 2019 at 10:34 AM Laurenz Albe 
wrote:

> Thomas Güttler wrote:
> > Now I realized: Nobody talked about Blobs.
> >
> > I guess most people do not store Blobs in PostgresSQL.
> >
> > Where do you store Blobs?
> >
> > (In my case Blobs are PDF/image files with size up to 20 MByte.
> > I do not talk about very big blobs which are several hundret MByte)
>
> Ideally outside the database, if they are many.
> Large databases are harder to backup than large file systems.
>
> If you keep 20MB binaries in the database, you'd use the "bytea" data type.
>
> Yours,
> Laurenz Albe
> --
> Cybertec | https://www.cybertec-postgresql.com
>
>
>


Query not producing expected result

2019-05-01 Thread Chuck Martin
I need help figuring out why a query is not returning the records I expect
it to. I'm searching on a DateTime column (timestamp without time zone -
not nullable). The query includes:

 AND event.Primaryresp_fkey = 511 AND event.DateTime <= 'May-1-2019'
 AND event.EventDone < 1

This does not return a record that has a DateTime value "May 1, 2019 9:52
AM". If I modify the query to:

 AND event.Primaryresp_fkey = 511 AND event.DateTime <= 'May-2-2019'
 AND event.EventDone < 1

it does return the record in question. I assume I am not doing the data
comparison correctly, but don't know why.

Chuck Martin
Avondale Software


Re: Query not producing expected result

2019-05-01 Thread Chuck Martin
Thanks, guys. It should have been obvious to me, but wasn't.

I found the correct result was returned with either

AND event.DateTime <= 'May-1-2019 24:00'

or

AND event.DateTime::date <= 'May-1-2019'

The latter seems best.

Chuck Martin
Avondale Software


On Wed, May 1, 2019 at 12:41 PM Tom Lane  wrote:

> Chuck Martin  writes:
> > I need help figuring out why a query is not returning the records I
> expect
> > it to. I'm searching on a DateTime column (timestamp without time zone -
> > not nullable). The query includes:
>
> >  AND event.Primaryresp_fkey = 511 AND event.DateTime <= 'May-1-2019'
> >  AND event.EventDone < 1
>
> > This does not return a record that has a DateTime value "May 1, 2019 9:52
> > AM".
>
> Well, no, since the implied value of the constant is 'May-1-2019 00:00'.
>
> If you only want 1-day precision of the comparison, maybe you should cast
> or truncate the timestamp down to date.
>
> regards, tom lane
>
>
>


Re: Query not producing expected result

2019-05-01 Thread Chuck Martin
Thanks for the extra information. It is indeed an indexed column. I'll have
to think some more about how to address this in a general way, as this
issue can come up all over. I suppose using

AND datetime <= 'May 1, 2019 24:00'

would produce the same as

AND datetime < 'May 2, 2019'

wouldn't it? I'm not sure one is easier to implement than the other.

Chuck Martin
Avondale Software


On Wed, May 1, 2019 at 1:16 PM Francisco Olarte 
wrote:

> Chuck:
>
> On Wed, May 1, 2019 at 6:56 PM Chuck Martin 
> wrote:
> > Thanks, guys. It should have been obvious to me, but wasn't.
> > I found the correct result was returned with either
> > AND event.DateTime <= 'May-1-2019 24:00'
> > or
> > AND event.DateTime::date <= 'May-1-2019'
> > The latter seems best.
>
> The latter may prevent index usage, if you've got one.
>
> One think I've said before. Dates are integer-like ( they are
> countable ), but timestamps are real-like ( they may be countable due
> to finite precision, like float or doubles are, but you should not
> count on it ). For real-like stuff it is normally better to work with
> half-open ranges, which in your case would translate to to query for
>
>event.DateTime < 'May-2-2019'  ( the minus-ininity <= DateTime
> would for the other end ).
>
> The reason is you can cover the whole DateTime domain with
> non-intersecting half-open ranges, but not with open or closed ones
> and, as a side effect, the starting point of a range is the same as
> the next one ( also, this does not need cast, better for the optimizer
> ) ( If your input is an end date I normally pass this to timestamp
> using ts < '$inclusive_end_date'::date + 1 ) ( I do lots of reports of
> this kind, and using this helps a lot once you get the hang of it
> after a couple tests ).
>
> ( I use half-open for dates to, for uniformity, and for being able to
> use FEBRUARY= dateColumn >= "YEAR-02-01' and dateColumn <
> "YEAR-03-01", no need to worry about leap years or remembering how
> many days each month has. Generally they are easier, the only con I've
> found is inability to use between ).
>
> Francisco Olarte.
>
>
>


Re: Query not producing expected result

2019-05-01 Thread Chuck Martin
Something like daterange would be a solution in some circumstances, but
this query is a user-generated one, and they don't have that much control
over the query. It has to be modified as needed behind the scenes so that
it produces the results they expect. In this instance, I'm now (given the
advice received here) inclined to check the value entered when searching
for a date, and if no time is entered, add '24:00' to the date.

Chuck Martin
Avondale Software


On Wed, May 1, 2019 at 1:32 PM Adrian Klaver 
wrote:

> On 5/1/19 10:15 AM, Francisco Olarte wrote:
> > Chuck:
> >
> > On Wed, May 1, 2019 at 6:56 PM Chuck Martin 
> wrote:
> >> Thanks, guys. It should have been obvious to me, but wasn't.
> >> I found the correct result was returned with either
> >> AND event.DateTime <= 'May-1-2019 24:00'
> >> or
> >> AND event.DateTime::date <= 'May-1-2019'
> >> The latter seems best.
> >
> > The latter may prevent index usage, if you've got one.
> >
> > One think I've said before. Dates are integer-like ( they are
> > countable ), but timestamps are real-like ( they may be countable due
> > to finite precision, like float or doubles are, but you should not
> > count on it ). For real-like stuff it is normally better to work with
> > half-open ranges, which in your case would translate to to query for
> >
> > event.DateTime < 'May-2-2019'  ( the minus-ininity <= DateTime
> > would for the other end ).
> >
> > The reason is you can cover the whole DateTime domain with
> > non-intersecting half-open ranges, but not with open or closed ones
> > and, as a side effect, the starting point of a range is the same as
> > the next one ( also, this does not need cast, better for the optimizer
> > ) ( If your input is an end date I normally pass this to timestamp
> > using ts < '$inclusive_end_date'::date + 1 ) ( I do lots of reports of
> > this kind, and using this helps a lot once you get the hang of it
> > after a couple tests ).
> >
> > ( I use half-open for dates to, for uniformity, and for being able to
> > use FEBRUARY= dateColumn >= "YEAR-02-01' and dateColumn <
> > "YEAR-03-01", no need to worry about leap years or remembering how
> > many days each month has. Generally they are easier, the only con I've
> > found is inability to use between ).
>
> Would daterange help/simplify?:
>
> create table dt_test(id integer, dt_fld date);
>
> insert into dt_test values (1, '2019-02-03'), (2, '2019-02-26'), (3,
> '2019-03-01');
>
> select dt_fld from dt_test where  dt_fld  <@  daterange('2019-02-01',
> '2019-03-01');
> dt_fld
> 
>   2019-02-03
>   2019-02-26
>
> >
> > Francisco Olarte.
> >
> >
>
>
> --
> Adrian Klaver
> adrian.kla...@aklaver.com
>
>
>


Re: Query not producing expected result

2019-05-01 Thread Chuck Martin
Ok, I see that my assumptions were incorrect. In this instance, the use of
< date+1 will return what is expected, where my solution might not have.
For other circumstances, I want to explore tsrange.

And, no, I'm not in Avondale, CA, but Decatur, GA (a few miles from
Avondale Estates, where I once lived).

Chuck Martin
Avondale Software


On Wed, May 1, 2019 at 1:52 PM Francisco Olarte 
wrote:

> On Wed, May 1, 2019 at 7:37 PM Chuck Martin 
> wrote:
> >
> > Something like daterange would be a solution in some circumstances, but
> this query is a user-generated one, and they don't have that much control
> over the query. It has to be modified as needed behind the scenes so that
> it produces the results they expect. In this instance, I'm now (given the
> advice received here) inclined to check the value entered when searching
> for a date, and if no time is entered, add '24:00' to the date.
>
> What I normally do for that is, if the user must enter a date, use
> $user_input::date+1 and always go to less than.
>
> But anyway your solution with <= is incorrect. And you have made the
> mistake probably because the 24:00 lead you to think postgres will
> split the timestamp, compare
> the date with may 1 and the time with 24:00, and that is not true. The
> less-than option plus one-day add will not lead you to that error.
>
> You can use <= with 23:59:59.999, will be good for
> some years if leap-seconds do not bite you.
>
> The problem is when the user enters a date, he wants a date search, so
> cast(dateTime as date) <= limit. When he enters a time he does not
> usually know what he is asking for ( normally when my users ask for
> 'May 1 23:15 they want to include up to 23:15:59, users think in
> "truncate to my precision, then search inclusively" ). But they begin
> to understand it when I ask "ok, twice a month bills, go 1..15 and
> 16..what ?", much easier to say [-MM-01 , -MM-16) and [
> -MM-16, (-MM-01)+1month)
>
> Francisco Olarte.
>
>
>


Column type changed "spontanously"?

2019-05-09 Thread Chuck Martin
I have several columns that were created as "timestamp without time zone",
but I changed them in 2014 to "timestamp with time zone". Recently, when I
got notified that times had suddenly changed, I checked and found the
columns had reverted to "timestamp without time zone." This seems
impossible, yet it seems to have happened. Any ideas on what could cause
this? My application has the privileges to do this, as it changed the data
type to support time zones. But there is no code that could change it back
not to support time zones.

The database in on

"PostgreSQL 9.3.1 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.4.7
20120313 (Red Hat 4.4.7-3), 64-bit"

What other information would help solve this?

Chuck Martin
Avondale Software


INSERT where not exists with foreign key

2019-05-20 Thread Chuck Martin
My Google foo isn't working on this question, probably because I don't
understand the question well enough. I'm using Postgres 11.3 on Centos 7.
I'm trying to insert a record in table A with a foreign key to table B, but
only where there is not already a foreign key in A to B. So assume this
simple structure:

Table A
A.keyInteger
A.something text
A.Bkey Integer [foreign key to table B, column B.key

Table B (or View C)
B.keyInteger
[more columns]

Thinking that it might simplify matters, I created a view to table B that
only includes records with no foreign key in Table A. But still, after
reading the documentation and Googling, I can't work out what seems like it
should be simple. Among the many things that didn't work is:

INSERT INTO A(something,A.Bkey)

VALUES ('text',
  (SELECT C.key FROM C)

But this didn't work because the subquery returned more than one value. Of
course I want it to return all values, but just one per insert.

I can do this outside of Postgres, but would like to learn how to do this
with SQL.

Chuck Martin
Avondale Software