Adding " before distinct value in select - sql

I have written the select to get the distinct table name (I have to use dba_tab_cols table because it's the only one with table names I have permission:
select distinct(table_name)||'"'||':' as SQL_TXT from dba_tab_cols where table_name = 'SAMPLE_TABLE'
I would like to add " before the table_name in this select, however when I write the following:
select '"'||distinct(table_name) I got the error:
**00936. 00000 - "missing expression"
*Cause:
*Action:**
I could not find similar topic, that is why I am sending this question.

The distinct is part of the select. So:
select distinct ('"' || table_name || '"' || ':') as SQL_TXT
from dba_tab_cols
where table_name = 'SAMPLE_TABLE';
select distinct is a "single" keyword that applies to all expressions in the select. It is not a function that applies to a single column.

Related

Query to count all rows in all Snowflake views

I'm trying to get an count of all the rows in a set of views in my Snowflake database.
The built-in row_count from information_schema.tables is not present in information_schema.views, unfortunately.
It seems I'd need to count all rows in each view, something like:
with view_name as (select table_name
from account_usage.views
where table_schema = 'ACCESS' and RIGHT(table_name,7) = 'CURRENT'
)
select count (*) from view_name;
But that returns only one results, instead of one for each line
If I change the select to include the view name, i.e.
select concat('Rows in ', view_name), count (*) from view_name;
…it returns the error "invalid identifier 'VIEW_NAME' (line 5)"
How can I show all results and include the view name?
You can create a query that looks at the information_schema to create a query that will go view by view getting its count:
select listagg(xx, ' union all ')
from (
select 'select count(*) c, \'' || x || '\' v from ' || x as xx
from (
select TABLE_CATALOG ||'.'|| TABLE_SCHEMA ||'."'||TABLE_NAME||'"' x
from KNOEMA_FORECAST_DATA_ATLAS.INFORMATION_SCHEMA.VIEWS
where table_schema='FORECAST'
)
)
See also How to find the number of rows for all views in a schema?

Oracle: if TABLE_A exists, return count(*), else return 0;

I want to use only one SQL statement, I have tried following one but failed:
SELECT decode(TABLE_COUNT, 0, 0, SELECT COUNT(*) FROM TABLE_A) FROM
(
SELECT COUNT(*) AS TABLE_COUNT FROM USER_TABLES WHERE TABLE_NAME = 'TABLE_A'
)
An example of the dbms_xmlgen approach that #RaymondNijland referred to in a comment:
create table table_a (id) as select level from dual connect by level <= 10;
select nvl(max(to_number(
xmlquery('/ROWSET/ROW/C/text()'
passing xmltype(dbms_xmlgen.getxml('select count(*) as c from ' || table_name))
returning content)
)), 0) as count
from user_tables
where table_name = 'TABLE_A';
COUNT
----------
10
drop table table_a purge;
select nvl(max(to_number(
xmlquery('/ROWSET/ROW/C/text()'
passing xmltype(dbms_xmlgen.getxml('select count(*) as c from ' || table_name))
returning content)
)), 0) as count
from user_tables
where table_name = 'TABLE_A';
COUNT
----------
0
You can easily extend this to query multiple tables at once, or all tables in a schema, etc., by changing the filter and adding a group-by clause.
The WITH clause may be of use in this case if the feature is available in the version of Oracle you are using. The following is what the code would look like.
NOTE: This is a SELECT statement even though it looks like PL/SQL code. The WITH clause supports the use of a PL/SQL declaration within it.
WITH
FUNCTION getCount(p_table_name IN VARCHAR2)
RETURN NUMBER IS
v_count NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM '||p_table_name INTO v_count;
RETURN mycount;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
SELECT getCount('hr.employee') FROM DUAL;
The WHEN OTHERS traps the error when the table does not exist and returns 0. If the table exists, it returns the count from the table.
Hope this works for you.

Update count of union

I have this query which is throwing a compilation error at the last ')'. The intellisense says 'Expected AS, ID or QUOTED_ID'.
What I am trying to do is - find the distinct values from the union of a table select and a function select, then get the count and update the column of another table with that value.
UPDATE #referees
SET [TotalKeywordCount] = (select count(*)
from (select Keyword
from [dbo].[RefereeFinderPersonKeyWord] P
where P.p_id=#referees.p_id
union
SELECT ltrim(rtrim(replace(Data, '''', '')))
from [SplitOne] (#keywords, ',')))
Any idea what I am doing wrong?
You need to add a name to the nested query that you use in the FROM of the query that pulls out the value for [TotalKeywordCount]. Below you have the code that assigns to it the name subquery:
UPDATE #referees
SET [TotalKeywordCount] = (select count(*) from (
select Keyword from [dbo].[RefereeFinderPersonKeyWord] P where P.p_id=#referees.p_id
union
SELECT ltrim(rtrim(replace(Data, '''', ''))) from [SplitOne] (#keywords, ',')) subquery )

Count how many percent of values on each column are nulls

Is there a way, through the information_schema or otherwise, to calculate how many percent of each column of a table (or a set of tables, better yet) are NULLs?
Your query has a number of problems, most importantly you are not escaping identifiers (which could lead to exceptions at best or SQL injection attacks in the worst case) and you are not taking the schema into account.
Use instead:
SELECT 'SELECT ' || string_agg(concat('round(100 - 100 * count(', col
, ') / count(*)::numeric, 2) AS ', col_pct), E'\n , ')
|| E'\nFROM ' || tbl
FROM (
SELECT quote_ident(table_schema) || '.' || quote_ident(table_name) AS tbl
, quote_ident(column_name) AS col
, quote_ident(column_name || '_pct') AS col_pct
FROM information_schema.columns
WHERE table_name = 'my_table_name'
ORDER BY ordinal_position
) sub
GROUP BY tbl;
Produces a query like:
SELECT round(100 - 100 * count(id) / count(*)::numeric, 2) AS id_pct
, round(100 - 100 * count(day) / count(*)::numeric, 2) AS day_pct
, round(100 - 100 * count("oDd X") / count(*)::numeric, 2) AS "oDd X_pct"
FROM public.my_table_name;
Closely related answer on dba.SE with a lot more details:
Check whether empty strings are present in character-type columns
In PostgreSQL, you can easily compute it using the statistics tables if your autovacuum setting is on (check it by SHOW ALL;). You can also set the vacuum interval to configure how fast your statistics tables should be updated. You can then compute the NULL percentage (aka, null fraction) simply using the query below:
select attname, null_frac from pg_stats where tablename = 'table_name'
Think there is not built-in features for this. You can make this self
Just walk thorough each column in table and calc count() for all rows and count() for rows where column is null.
There is possible and optimize this for one query for one table.
OK, I played around a little and made a query that returns a query--or queries if you use LIKE 'my_table%' instead of = 'my_table_name':
SELECT 'select '|| string_agg('(count(*)::real-count('||column_name||')::real)/count(*)::real as '||column_name||'_percentage ', ', ') || 'from ' || table_name
FROM information_schema.columns
WHERE table_name LIKE 'my_table_name'
GROUP BY table_name
It returns a ready-to-run SQL query, like:
"SELECT (count(*)::real-count(id)::real)/count(*)::real AS id_percentage , (count(*)::real-count(value)::real)/count(*)::real AS value_percentage FROM my_table_name"
id_percentage;value_percentage
0;0.0177515
(The caps didn't go exactly right for readability.)

Concatenate and use in where clause oracle plsql

I have to concatenate two fields and use concatenated field in where clause but it gives me invalid identifier. How to solve this query.
select i.FIRST_NAME || ' - ' || i.LAST_NAME as NAME, i.* from CONTACT i
where NAME = 'JOHN - HANKS'
This gives me
ORA-00904: "NAME": invalid identifier
00904. 00000 - "%s: invalid identifier"
You cannot use a column alias at the same level. Just use a subquery (or repeat the expression):
select c.*
from (select i.FIRST_NAME || ' - ' || i.LAST_NAME as NAME, i.*
from CONTACT i
) c
where c.NAME = 'JOHN - HANKS';
The WITH clause is also a good alternative, better readability. Also, if the subquery is to be used multiple times, it is even better.
WITH data as(
select i.FIRST_NAME || ' - ' || i.LAST_NAME as NAME, i.* from CONTACT i)
select * from data where name = 'JOHN - HANKS';
select i.FIRST_NAME || ' - ' || i.LAST_NAME as NAME, i.* from CONTACT i
where i.first_name ||'~'||i.last_name = 'JHON~HANKS';