PyCharm has outdated SQL dialects? - postgresql

I'm working with PostgresQL database with a python script. I have a query like this:
UPDATE orders SET id=%s, client=%s, contents=%s, adress=%s, detail=%s, price=%s HAVING MIN(id)
It works fine, but PyCharm says that "having" statement doesn't exist and i should use "where" (while "where" gives an exception in this query because I'm using "MIN"). And I have SQL dialect in PyCharm set to "PostgresQL". Any ways to fix this annoying issue?
UPD: my bad, this query isn't working. It somehow didn't throw an exception in python, but the row in database wasn't updated. Then what query should I use to update row with the least id?

You can get min(id) in the same query with either a sub-query or a CTE. Perhaps something like:
update some_tbl
set col = 1
where id = (select min(id)
from some_tbl
) ;
OR
with lowers(mid) as
(select min(id)
from some_tbl
)
update some_tbl st
set col = 1
from lowers l
where st.id = l.mid;

Related

MemSql > workaround for SELECT ... FOR UPDATE

I am using MemSql as my DB and I need to have SELECT ... FOR UPDATE functionality. However it is not supported in 6.5 version, which I am using. Is there any workaround for this problem?
My problem is as follows: multiple processes pick a single record (that has not been process yet) from the same table, do some job out of SQL code then do UPDATE for marking the record as processed. If I had a possibility to do SELECT ... FOR UPDATE then I could lock the record for assuring that only one process can pick it.
As a workaround that I can think of is using some LockToken column and do something like
UPDATE Tbl SET LockToken = 'a_unique_token' WHERE LockToken IS NULL LIMIT 1;
SELECT * FROM Tbl WHERE LockToken = 'a_unique_token';
but in this case I get
Error Code: 1749. Feature 'UPDATE...LIMIT must be constrained to a single partition' is not supported by MemSQL Distributed.
I could also do the job with LOCK TABLES, but according to this they are not supported as well.
Is there any workaround to this type of problem?
Yes, your workaround is a good idea. One way you could workaround that error is to pick a specific row to lock instead of using LIMIT 1, like UPDATE Tbl SET LockToken = 'a_unique_token' WHERE LockToken IS NULL and id = (select id from Tbl WHERE LockToken IS NULL limit 1). (Or you could use (select min(id) from Tbl WHERE LockToken IS NULL) or something similar to pick an id depending on what you want.) This should work well if you have an index on id.
Also, you could check out version 6.7 where select for update is now supported: https://docs.memsql.com/sql-reference/v6.7/select/.

Postgresql DISTINCT and other fields gives Missing FROM-clause

I want to search DISTINCT on a Postgresql 9.4 table with about 300 000 records. It takes almost 8 seconds. I read on this post that using this could speed it up. And it really did. Down to 0.26 sec.
SELECT COUNT(*) FROM (SELECT DISTINCT column_name FROM table_name) AS temp;
Is much faster than
COUNT(DISTINCT(column_name))
When I write this I get the result but I want to add a WHERE clause.
This works but takes over 7 sec.
SELECT COUNT(DISTINCT(species)) FROM darwincore2
WHERE darwincore2.dataeier ILIKE '%nnog%'
This works (0.26 sec.) but fails when I add the WHERE clause:
SELECT COUNT(*) FROM (SELECT DISTINCT species FROM darwincore2) as temp
WHERE darwincore2.dataeier ILIKE '%nnog%'
with:
ERROR: missing FROM-clause entry for table "darwincore2"
Anyone know how I can fix this? Or am I trying to do something that does not work??
The WHERE clause should be in the subquery:
SELECT COUNT(*)
FROM (
SELECT DISTINCT species
FROM darwincore2
WHERE darwincore2.dataeier ILIKE '%nnog%'
) as temp

Postgres JDBC Numbered Parameters

I have a table in a Postgres 9.3 database with a json column like this:
CREATE mytable (
mycolumn json
)
I would like to execute queries from a Java application that look like this:
SELECT
mycolumn->>'somefield',
count(*)
FROM
mytable
GROUP BY
mycolumn->>'somefield'
When I try to use a PreparedStatement like this:
SELECT
mycolumn->>?,
count(*)
FROM
mytable
GROUP BY
mycolumn->>?
I get the following error:
PSQLException: ERROR: column "mytable.mycolumn" must appear in the GROUP BY clause or be used in an aggregate function
It makes sense that this happens because Postgres cannot guarantee that the two positional parameters are the same.
Using psql, I can prepare a statement like this:
PREPARE mystatement AS
SELECT
mycolumn->>$1,
count(*)
FROM
mytable
GROUP BY
mycolumn->>$1
Is it possible to do this with JDBC?
No, this isn't possible. JDBC only has positional parameters, and therefor the PostgreSQL driver will render it as:
PREPARE mystatement AS
SELECT
mycolumn->>$1,
count(*)
FROM
mytable
GROUP BY
mycolumn->>$2
And as the value of $1 is not necessarily the same as $2, the parser of PostgreSQL will reject it as you are potentially not grouping on the same column.
The solution might be to do:
SELECT a.aColumnLabel, count(*)
FROM (
SELECT mycolumn->>? as aColumnLabel
FROM mytable
) a
GROUP BY a.aColumnLabel

TSQL bulk update with select subquery

I'm more familiar with Oracle so the syntax of SQL Server 2008 is throwing me. I'm trying to perform an update of multiple rows with a query equivalent to
update Table
set type = 'typeA'
where id in
(select id from Table where type='typeB')
I am receiving the following error:
Msg 512, Level 16, State 1, Procedure Assigned_To_Email, Line 19
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Searching for a TSQL specific solution I tried the following syntax but received the same error.
update a
set type = 'typeA'
from Table a
join Table b
on a.id = b.id
where b.type='typeB'
I've read that an update with the subquery should work, but it's not been my experience. Is there something more basic missing here?
Thanks for any help!
Your update statement does not have to use a sub-query or a join.
update Table
set type = 'typeA'
where type = 'typeB'

Is there a way to find TOP X records with grouped data?

I'm working with a Sybase 12.5 server and I have a table defined as such:
CREATE TABLE SomeTable(
[GroupID] [int] NOT NULL,
[DateStamp] [datetime] NOT NULL,
[SomeName] varchar(100),
PRIMARY KEY CLUSTERED (GroupID,DateStamp)
)
I want to be able to list, per [GroupID], only the latest X records by [DateStamp]. The kicker is X > 1, so plain old MAX() won't cut it. I'm assuming there's a wonderfully nasty way to do this with cursors and what-not, but I'm wondering if there is a simpler way without that stuff.
I know I'm missing something blatantly obvious and I'm gonna kick myself for not getting it, but .... I'm not getting it. Please help.
Is there a way to find TOP X records, but with grouped data?
According to the online manual, Sybase 12.5 supports WINDOW functions and ROW_NUMBER(), though their syntax differs from standard SQL slightly.
Try something like this:
SELECT SP.*
FROM (
SELECT *, ROW_NUMBER() OVER (windowA ORDER BY [DateStamp] DESC) AS RowNum
FROM SomeTable
WINDOW windowA AS (PARTITION BY [GroupID])
) AS SP
WHERE SP.RowNum <= 3
ORDER BY RowNum DESC;
I don't have an instance of Sybase, so I haven't tested this. I'm just synthesizing this example from the doc.
I made a mistake. The doc I was looking at was Sybase SQL Anywhere 11. It seems that Sybase ASA does not support the WINDOW clause at all, even in the most recent version.
Here's another query that could accomplish the same thing. You can use a self-join to match each row of SomeTable to all rows with the same GroupID and a later DateStamp. If there are three or fewer later rows, then we've got one of the top three.
SELECT s1.[GroupID], s1.[Foo], s1.[Bar], s1.[Baz]
FROM SomeTable s1
LEFT OUTER JOIN SomeTable s2
ON s1.[GroupID] = s2.[GroupID] AND s1.[DateStamp] < s2.[DateStamp]
GROUP BY s1.[GroupID], s1.[Foo], s1.[Bar], s1.[Baz]
HAVING COUNT(*) < 3
ORDER BY s1.[DateStamp] DESC;
Note that you must list the same columns in the SELECT list as you list in the GROUP BY clause. Basically, all columns from s1 that you want this query to return.
Here's quite an unscalable way!
SELECT GroupID, DateStamp, SomeName
FROM SomeTable ST1
WHERE X <
(SELECT COUNT(*)
FROM SomeTable ST2
WHERE ST1.GroupID=ST2.GroupID AND ST2.DateStamp > ST1.DateStamp)
Edit Bill's solution is vastly preferable though.