Apply MAX(LENGTH) on all columns of a table - amazon-redshift

I want to check the MAX(LENGTH) of all VARCHAR columns of my Redshift table, so I have an idea of a better limitation I could put on the column sizes. (Right now all columns are VARCHAR(65535))
I can write a query like:
SELECT MAX(LENGTH(col1)), MAX(LENGTH(col2)), ...
FROM my_table
But isn't there a way I could write my query so it basically says "apply this for every column"? I've tried the answer from this post but it seems it only applies to classic PostgreSQL

You can use the following SQL the generate your select
select sql from (
select 1 o, 'select ' sql
union
select 2, 'max(length('+attname+')),'
from pg_class c
join pg_attribute a on c.oid = a.attrelid
where relname = '<your_table>'
and attnum > 0
union
select 3, 'from <your_table>'
)
order by o
The output will look like this
select
max(length(col1)),
max(length(col2)),
...
max(length(coln)), -- <- remove the last comma
from <your_table>
You can run this sql to get all max lengths from your table
Please let me know if this helps you.

Related

Delete .. from .. join, same syntax for postgresql and oracle

I need to execute the same exact query on oracle and postgresql, in which i need to delete rows from table 1, using a join on table 2.
I already had a working query, but it stopped working for oracle with 1000+ results in the "IN" statement.
delete from t1
where
t1.oid IN
(SELECT oid from t2 WHERE [condition])
I've read about joins but postgresql uses the "using" keyword instead
DELETE [target table]
FROM [table1]
INNER JOIN [table2]
ON [table1.[joining column] = [table2].[joining column]
WHERE [condition]
Any help is appreciated, thanks
Oracle does not support a JOIN or USING or something similar for the DELETE statement. Your only choices are IN or EXISTS, if you need something that works on Postgres and Oracle.
If an IN condition is too slow then try an EXISTS condition:
delete from t1
where exists (select *
from t2
where t2.oid = t1.oid
and [condition])
You can use and multi-dimensional IN expression (which should work up to 100,000 items):
DELETE FROM t1
WHERE ( t1.oid, 1 ) IN ( SELECT oid, 1 FROM t2 );
or EXISTS (which should work for any volume of rows):
DELETE FROM t1
WHERE EXISTS ( SELECT 1 FROM t2 WHERE t1.oid = t2.oid );
And add the WHERE condition into the sub-query as required.
PostgreSQL db<>fiddle
Oracle db<>fiddle

How to optimize SELECT DISTINCT when using multiple Joins?

I have read that using cte's you can speed up a select distinct up to 100 times. Link to the website . They have this following example:
USE tempdb;
GO
DROP TABLE dbo.Test;
GO
CREATE TABLE
dbo.Test
(
data INTEGER NOT NULL,
);
GO
CREATE CLUSTERED INDEX c ON dbo.Test (data);
GO
-- Lots of duplicated values
INSERT dbo.Test WITH (TABLOCK)
(data)
SELECT TOP (5000000)
ROW_NUMBER() OVER (ORDER BY (SELECT 0)) / 117329
FROM master.sys.columns C1,
master.sys.columns C2,
master.sys.columns C3;
GO
WITH RecursiveCTE
AS (
SELECT data = MIN(T.data)
FROM dbo.Test T
UNION ALL
SELECT R.data
FROM (
-- A cunning way to use TOP in the recursive part of a CTE :)
SELECT T.data,
rn = ROW_NUMBER() OVER (ORDER BY T.data)
FROM dbo.Test T
JOIN RecursiveCTE R
ON R.data < T.data
) R
WHERE R.rn = 1
)
SELECT *
FROM RecursiveCTE
OPTION (MAXRECURSION 0);
How would one apply this to a query that has multiple joins? For example i am trying to run this query found below, however it takes roughly two and a half minutes. How would I optimize this accordingly?
SELECT DISTINCT x.code
From jpa
INNER JOIN jp ON jpa.ID=jp.ID
INNER JOIN jd ON (jd.ID=jp.ID And jd.JID=3)
INNER JOIN l ON jpa.ID=l.ID AND l.CID=3
INNER JOIN fa ON fa.ID=jpa.ID
INNER JOIN x ON fa.ID=x.ID
1) GROUP BY on every column worked faster for me.
2) If you have duplicates in some of the tables then you can also pre select that and join from that as an inner query.
3) Generally you can nest join if you expect that this join will limit data.
SQL join format - nested inner joins

How can I test if a column exists in a table using an SQL statement

Is there a simple alternative in PostgreSQL to this statement produced in Oracle?
select table_name from user_tab_columns
where table_name = myTable and column_name = myColumn;
I am then testing whether the query returns anything so as to prove the column exists.
I am aware that using psql I can find these out individually but this is required to produce a result in a program I am writing to validate that a requested attribute field exists in my database table.
Try this :
SELECT column_name
FROM information_schema.columns
WHERE table_name='your_table' and column_name='your_column';
Accepted answer is correct, but is missing the schema and nicer output (True/False):
SELECT EXISTS (SELECT 1
FROM information_schema.columns
WHERE table_schema='my_schema' AND table_name='my_table' AND column_name='my_column');
Simpler and SQLi-safe using PostgreSQL's object identifier types:
SELECT true
FROM pg_attribute
WHERE attrelid = 'myTable'::regclass -- cast to a registered class (table)
AND attname = 'myColumn'
AND NOT attisdropped -- exclude dropped (dead) columns
-- AND attnum > 0 -- exclude system columns (you may or may not want this)
System catalogs are many times faster than querying the notoriously convoluted information_schema (but still just milliseconds for a single query). See:
Get column names and data types of a query, table or view
Read about the significance of the columns in the manual.
While building dynamic SQL with the column name supplied as parameter, use quote_ident() to defend against SQL injection:
...
AND attname = quote_ident('myColumn');
Works for tables outside the search_path, too:
...
WHERE attrelid = 'mySchema.myTable'::regclass
...
Unlike Oracle, PostgreSQL supports the ANSI standard INFORMATION_SCHEMA views.
The corresponding standard view to Oracle's user_tab_columns is information_schema.columns
http://www.postgresql.org/docs/current/static/infoschema-columns.html
SELECT attname
FROM pg_attribute
WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'YOURTABLENAME')
AND attname = 'YOURCOLUMNNAME';
Of course, replace YOURTABLENAME and YOURCOLUMNNAME with the proper values. If a row is returned, a column with that name exists, otherwise it does not.
Here is a similar variant of Erwin Brandstetter answer.
Here we check schema too in case we have similar tables in different schema.
SELECT TRUE FROM pg_attribute
WHERE attrelid = (
SELECT c.oid
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE
n.nspname = CURRENT_SCHEMA()
AND c.relname = 'YOURTABLENAME'
)
AND attname = 'YOURCOLUMNNAME'
AND NOT attisdropped
AND attnum > 0

Select query to find the unmatched records from selected values using in function in Oracle 10g

I am using IN clause for column "job_no". In this in clause i checking 1000 values, query retreiving the values but some of the job number are not existed, then how to find unmattched values in the in clause.
assuming you really are using Oracle:
create type table_of_integers is table of integer;
/
select * from table(table_of_integers(1, 2, 3))
where column_value not in (select job_no from my_table);
or you should be able to achieve the same thing using an outer join, such as this example for postgres:
select *
from (select unnest(array[1, 2, 3]) as job_no) j
left outer join my_table using(job_no)
where my_table.job_no is null;
Insert the values into a temporary table instead and do a LEFT OUTER JOIN to join with your data.

Using query to set the column type in PostgreSQL

After the excellent answer by Alexandre GUIDET, I attempted to run the following query:
create table egg (id (SELECT
pg_catalog.format_type(a.atttypid, a.atttypmod) as Datatype
FROM
pg_catalog.pg_attribute a
WHERE
a.attnum > 0
AND NOT a.attisdropped
AND a.attrelid = (
SELECT c.oid
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname ~ '^(TABLENAME)$'
AND pg_catalog.pg_table_is_visible(c.oid)
)
and a.attname = 'COLUMNNAME'));
PostgreSQL, however, complains about incorrect syntax. Specifically it says that I cannot write: create table egg (id (SELECT.
Are there any workarounds? Can't I convert the result of a query to text and reuse it as a query?
There is a much simpler way to do that.
SELECT pg_typeof(col)::text FROM tbl LIMIT 1
Only precondition is that the template table holds at least one row. See the manual on pg_typeof()
As Milen wrote, you need to EXECUTE dynamic DDL statements like this.
A much simpler DO statement:
DO $$BEGIN
EXECUTE 'CREATE TABLE egg (id '
|| (SELECT pg_typeof(col)::text FROM tbl LIMIT 1) || ')';
END$$;
Or, if you are not sure the template table has any rows:
DO $$BEGIN
EXECUTE (
SELECT format('CREATE TABLE egg (id %s)'
, format_type(atttypid, atttypmod))
FROM pg_catalog.pg_attribute
WHERE attrelid = 'tbl'::regclass -- name of template table
AND attname = 'col' -- name of template column
AND attnum > 0 AND NOT attisdropped
);
END$$;
These conditions seem redundant, since you look for a specific column any
format() requires Postgres 9.1+.
Related:
How to check if a table exists in a given schema
You can either convert that query to a function or (if you have Postgres 9.0) to an anonymous code block:
DO $$DECLARE the_type text;
BEGIN
SELECT ... AS datatype INTO the_type FROM <the rest of your query>;
EXECUTE 'create table egg ( id ' || the_type || <the rest of your create table statement>;
END$$;
You can either have a table a definition or a query, but not both. Maybe your thinking of the select into command.