Aggregation function is different in version 8.4 and 9.5? - postgresql

I have a query like this.
SELECT companies.id, companies.code, MAX(disclosures.filed_at) disclosure_filed_at
FROM \"companies\" INNER JOIN \"disclosures\" ON \"disclosures\".\"company_id\" = \"companies\".\"id\"
GROUP BY companies.id
This query works in Postgresql 9.5.2, but it failed in version 8.4.20 with an error.
PG::GroupingError: ERROR: column "companies.code" must appear in the GROUP BY clause or be used in an aggregate function
If I add companies.code to GROUP BY clause, then it works. But when I select by companies.*, I can't group by companies.*.
Should I write all columns in version 8.4 to use *?

The Postgres behavior is supported by the ANSI standard. The reason is that the id not only defines each row in companies, but it is defined to do so (using a unique or primary key constraint, although I'm not sure if this works in Postgres for a unique constraint).
Hence, the database knows that it can safely refer to any other column from the same row. This is called "functional dependency".
This feature has also now been added to MySQL (documented here). You might find that documentation easier to follow than the Postgres description:
When GROUP BY is present, or any aggregate functions are present, it
is not valid for the SELECT list expressions to refer to ungrouped
columns except within aggregate functions or when the ungrouped column
is functionally dependent on the grouped columns, since there would
otherwise be more than one possible value to return for an ungrouped
column. A functional dependency exists if the grouped columns (or a
subset thereof) are the primary key of the table containing the
ungrouped column.

Related

PostgreSQL 14 and Unique Index Issue

I have a database I am importing and it has a unique index for a field that is null. In PostgreSQL 13 it was not an issue but in 14 it now longer allows the import as null is no longer null but a value.
Is there a setting where null is treated like it should be instead of as a value?
The behavior has not changed in PostgreSQL v14. If the import doesn't work in the database, the only possible explanation is that you have defined the column NOT NULL in one database, but not in the other one (or used a similar check constraint).
PostgreSQL v15 introduces this standard conforming additional clause for unique constraints:
UNIQUE NULLS [NOT] DISTINCT
If you define a unique constraint with NULLS NOT DISTINCT in v15, it will behave differently from prior versions. However, the default is still UNIQUE NULLS DISTINCT.
when I query the table, the null values are being set as '' during the import, so it fails after the first row. Not sure what changed (other than upgrading to 14.5). Going to reach out to the importer company, I can insert multiple null values so somethings up on their end.

Appending array during Postgresql upsert & getting ambiguous column error

When trying to do a query like below:
INSERT INTO employee_channels (employee_id, channels)
VALUES ('46356699-bed1-4ec4-9ac1-76f124b32184', '{a159d680-2f2e-4ba7-9498-484271ad0834}')
ON CONFLICT (employee_id)
DO UPDATE SET channels = array_append(channels, 'a159d680-2f2e-4ba7-9498-484271ad0834')
WHERE employee_id = '46356699-bed1-4ec4-9ac1-76f124b32184'
AND NOT lower(channels::text)::text[] #> ARRAY['a159d680-2f2e-4ba7-9498-484271ad0834'];
I get the following error
[42702] ERROR: column reference "channels" is ambiguous Position: 245
The specific reference to channels it's referring to is the 'channels' inside array_append.
channels is a CITEXT[] data type
You may need to specify the EXCLUDED table in your set statement.
SET channels = array_append(EXCLUDED.channels, 'a159d680-2f2e-4ba7-9498-484271ad0834')
When using the ON CONFLICT DO UPDATE clause the values that aren't inserted because of the conflict are stored in the EXCLUDED table. Its an ephemeral table you don't have to actually make, the way NEW and OLD are in triggers.
From the PostgreSQL Manual:
conflict_action specifies an alternative ON CONFLICT action. It can be either DO NOTHING, or a DO UPDATE clause specifying the exact
details of the UPDATE action to be performed in case of a conflict.
The SET and WHERE clauses in ON CONFLICT DO UPDATE have access to the
existing row using the table's name (or an alias), and to rows
proposed for insertion using the special excluded table. SELECT
privilege is required on any column in the target table where
corresponding excluded columns are read.
Note that the effects of all per-row BEFORE INSERT triggers are reflected in excluded values, since those effects may have contributed
to the row being excluded from insertion.

select all columns except two in q kdb historical database

In output I want to select all columns except two columns from a table in q/kdb historical database.
I tried running below query but it does not work on hdb.
delete colid,coltime from table where date=.z.d-1
but it is failing with below error
ERROR: 'par
(trying to update a physically partitioned table)
I referred https://code.kx.com/wiki/Cookbook/ProgrammingIdioms#How_do_I_select_all_the_columns_of_a_table_except_one.3F but no help.
How can we display all columns except for two in kdb historical database?
The reason you are getting par error is due to the fact that it is a partitioned table.
The error is documented here
trying to update a partitioned table
You cannot directly update, delete anything on a partitioned table ( there is a separate db maintenance script for that)
The query you have used as fix is basically selecting the data first in-memory (temporarily) and then deleting the columns, hence it is working.
delete colid,coltime from select from table where date=.z.d-1
You can try the following functional form :
c:cols[t] except `p
?[t;enlist(=;`date;2015.01.01) ;0b;c!c]
Could try a functional select:
?[table;enlist(=;`date;.z.d);0b;{x!x}cols[table]except`colid`coltime]
Here the last argument is a dictionary of column name to column title, which tells the query what to extract. Instead of deleting the columns you specified this selects all but those two, which is the same query more or less.
To see what the functional form of a query is you can run something like:
parse"select colid,coltime from table where date=.z.d"
And it will output the arguments to the functional select.
You can read more on functional selects at code.kx.com.
Only select queries work on partitioned tables, which you resolved by structuring your query where you first selected the table into memory, then deleted the columns you did not want.
If you have a large number of columns and don't want to create a bulky select query you could use a functional select.
?[table;();0b;{x!x}((cols table) except `colid`coltime)]
And show all columns except a subset of columns. The column clause expects a dictionary hence I am using the function {x!x} to convert my list to a dictionary. See more information here
https://code.kx.com/q/ref/funsql/
As nyi mentioned, if you want to permanently delete columns from an historical database you can use the deleteCol function in the dbmaint tools https://github.com/KxSystems/kdb/blob/master/utils/dbmaint.md

Enforcing case insensitive column references in T-SQL

I am working with SQL Server 2014. I have dynamically generated SQL which looks like this (simplified for brevity):
with CTE as
(
select field as [field], field as [Field]
from myTable
)
select [field], [Field]
from CTE
The above however results in this error:
The column 'Field' was specified multiple times for 'CTE'.
I would expect/want this to work because the 2 columns are in fact unique, accounting for case. Is there anyway we can ask SQL (via some SET option maybe) to treat them as unique?
My dynamically generated SQL is very complex and it's very difficult to identify such 'duplicates' and 'combine' them.
From a theoretical perspective, you could change the collation of your database to a case-sensitive option. Case-sensitive database/server collations will also consider the case sensitivity of aliases. Table column collations, and collating a column in a select will not.
Changing database/server collation will change a whole lot else though. It would be a very extreme change to fix an alias issue and I doubt it is a viable solution for you.
That said, if your dynamic SQL is able to see that the alias field already exists and use the capitalized alias Field for the next instance of the same column, I would think you could simply adjust that to be field1, field2 etc. You can always re-alias those to whatever you want in your outer/final select, they just need to be unique in the CTE query.

Data type mismatch in MS Access SQL sub-query

Alright, this query will not run and returns a data type mismatch error. This error did not start until I attempted to join two tables within the sub-query in the WHERE clause.
The two tables I am attempting to join are the exact two tables that are joined in the primary query. Each table contains a column, CRD Number. In one table, it is stored as text, in the other, it is stored as number. This is why I have used the CStr() function to cast the numerical column as a textual column. This worked beautifully for the primary query (thank Stack Overflow!) but when I attempted to do the same exact join in the sub-query, I received the data type mismatch error.
Here is a picture, with a small arrow and text box to highlight the area which I (99% sure) believe is causing the problem. Again, the problem only arose when I attempted to join these two tables in the sub-query. If the join is removed, the query will run. (Although the sub-query will not return the correct results, thus making my primary query useless)
*All my Access DB's are set to accept Standard T-SQL syntax, so I will also tag this as T-SQL
I think the difference is probably that in the primary query you are excluding the cases where Crd Number is null, but in the subquery you are not. I don't have Access installed to be able to test, but I would bet it will work if you add to the subquery where clause.
sp.CRD_NUMBER is not null and dtp.CRD_NUMBER is not null
I suspect that the function CStr() is having a problem with null values, but then again, I can't test this to see if that would make a difference.