Apex. How to output NULL values too? - sql

I had a question with a single sql query related to an interactive table in apex
Here, look, I prescribe a request in which I print all the existing artists in the database, but I only have entries where all the fields have values, and those in which at least one NULL are not displayed
select artist.name as "Artist", country.name as "Country" , city.name as "City of foundation", label.name as "Label of records"
from artist, country, city, label
where artist.country = country_id
and artist.city = city_id
and city.country = country_id
and artist.label = label_id
How to fix it?
https://i.stack.imgur.com/ZRYzm.png

As you didn't provide test case (a screenshot isn't quite enough - at least, not to me), I'll try to show what might be going on using Scott's schema.
There are 4 departments: note department 40, and the fact that nobody works in it:
SQL> select * from dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> select * from emp where deptno = 40;
no rows selected
If you want to display all 4 departments and employees who work in them, you'd join EMP and DEPT table. Outer join lets you display department 40 (which, as we saw, has no employees):
SQL> select d.deptno, d.dname, e.ename
2 from dept d left join emp e on e.deptno = d.deptno --> outer join is here
3 order by d.deptno;
DEPTNO DNAME ENAME
---------- -------------- ----------
10 ACCOUNTING CLARK
10 ACCOUNTING MILLER
10 ACCOUNTING KING
20 RESEARCH JONES
20 RESEARCH SMITH
20 RESEARCH SCOTT
20 RESEARCH FORD
20 RESEARCH ADAMS
30 SALES WARD
30 SALES TURNER
30 SALES ALLEN
30 SALES JAMES
30 SALES MARTIN
30 SALES BLAKE
40 OPERATIONS --> this is what you're looking for
15 rows selected.
SQL>
You'd get the same result using the old Oracle's (+) outer join operator. You'd rather switch to modern joins and avoid that operator, though.
SQL> select d.deptno, d.dname, e.ename
2 from dept d, emp e
3 where d.deptno = e.deptno (+) --> the old outer join operator
4 order by d.deptno;
DEPTNO DNAME ENAME
---------- -------------- ----------
10 ACCOUNTING CLARK
10 ACCOUNTING MILLER
10 ACCOUNTING KING
20 RESEARCH JONES
20 RESEARCH SMITH
20 RESEARCH SCOTT
20 RESEARCH FORD
20 RESEARCH ADAMS
30 SALES WARD
30 SALES TURNER
30 SALES ALLEN
30 SALES JAMES
30 SALES MARTIN
30 SALES BLAKE
40 OPERATIONS
15 rows selected.
SQL>

Related

SQL subquery COUNT for Oracle

In my Oracle database, I have two tables T1 with primary key k1, and T2 with a composite primary key k1, k2. I would like to select all columns in T1 along with the number of lines in T2 such as T1.k1 = T2.k1.
It seems simple, but I can't figure how to use the COUNT function to get this result, any idea ?
I don't have your tables so I'll try to illustrate it using Scott's sample emp and dept tables:
SQL> select * from dept t1 order by t1.deptno;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> select deptno, empno, ename from emp order by deptno;
DEPTNO EMPNO ENAME
---------- ---------- ----------
10 7782 CLARK --> 3 employees in deptno 10
10 7839 KING
10 7934 MILLER
20 7566 JONES --> 5 employees in deptno 20
20 7902 FORD
20 7876 ADAMS
20 7369 SMITH
20 7788 SCOTT
30 7521 WARD --> 6 employees in deptno 30
30 7844 TURNER
30 7499 ALLEN
30 7900 JAMES
30 7698 BLAKE
30 7654 MARTIN
--> 0 employees in deptno 40
14 rows selected.
SQL>
A few options you might try:
Correlated subquery:
SQL> select t1.*,
2 (select count(*) from emp t2 where t2.deptno = t1.deptno) cnt
3 from dept t1
4 order by t1.deptno;
DEPTNO DNAME LOC CNT
---------- -------------- ------------- ----------
10 ACCOUNTING NEW YORK 3
20 RESEARCH DALLAS 5
30 SALES CHICAGO 6
40 OPERATIONS BOSTON 0
SQL>
(Outer) join with the COUNT function and the GROUP BY clause:
SQL> select t1.*, count(t2.rowid) cnt
2 from dept t1 left join emp t2 on t2.deptno = t1.deptno
3 group by t1.deptno, t1.dname, t1.loc
4 order by t1.deptno;
DEPTNO DNAME LOC CNT
---------- -------------- ------------- ----------
10 ACCOUNTING NEW YORK 3
20 RESEARCH DALLAS 5
30 SALES CHICAGO 6
40 OPERATIONS BOSTON 0
SQL>
(Outer) join with the COUNT function in its analytic form:
SQL> select distinct t1.*,
2 count(t2.rowid) over (partition by t1.deptno) cnt
3 from dept t1 left join emp t2 on t2.deptno = t1.deptno
4 order by t1.deptno;
DEPTNO DNAME LOC CNT
---------- -------------- ------------- ----------
10 ACCOUNTING NEW YORK 3
20 RESEARCH DALLAS 5
30 SALES CHICAGO 6
40 OPERATIONS BOSTON 0
SQL>

About "group function is not allowed here"

I have a table with job, salary and date columns. I am writing the following query in PL/SQL, but I am getting an error
group function is not allowed here
delete employees where date = '06-05-2020 'and avg (salary)> 5500;
How can I solve this problem?
Your query makes no sense (to me, at least). What does that average salary represent? Whose average salary?
Here's an example based on Scott's EMP table; I'm going to delete employees who were hired on 3th of December 1981 and work in department whose employees' average salary is higher than 2000.
Sample data:
SQL> select deptno, ename, sal, hiredate from emp order by deptno, ename;
DEPTNO ENAME SAL HIREDATE
---------- ---------- ---------- ----------
20 ADAMS 1100 12.01.1983
20 FORD 3000 03.12.1981 --> this
20 JONES 2975 02.04.1981
20 SCOTT 3000 09.12.1982
20 SMITH 800 17.12.1980
30 ALLEN 1600 20.02.1981
30 BLAKE 2850 01.05.1981
30 JAMES 950 03.12.1981 --> this
30 MARTIN 1250 28.09.1981
30 TURNER 1500 08.09.1981
30 WARD 1250 22.02.1981
11 rows selected.
Averege salaries per department:
SQL> select deptno, avg(sal) avg_salary
2 from emp
3 group by deptno
4 order by avg_salary desc;
DEPTNO AVG_SALARY
---------- ----------
20 2175 --> higher than 2000
30 1566,66667
So: I'm looking for employees who work in department 20 (as only that department has average salaries higher than 2000) and who were hired on 03.12.1981 (James and Ford, but only Ford works in department 20):
SQL> delete from emp
2 where hiredate = date '1981-12-03'
3 and deptno in (select deptno
4 from emp
5 group by deptno
6 having avg(sal) > 2000
7 );
1 row deleted.
Is Ford still in there?
SQL> select * From emp where ename = 'FORD';
no rows selected
SQL>
Nope, deleted.
Now, your turn.

How to transfer Oracle (+) operator with joins to Spark SQL?

I have a part of code in Oracle as this:
SELECT
t1.col1,
t1.col2,
t2.col1,
t2,col2
FROM
t1,
t2
WHERE
t1.col1 <> 121
AND t1.col1 = t2.col1(+)
AND t1.col2 = t2.col2(+)
AND 'ABC' = t2.col3(+)
How to transfer it to Spark SQL assuming tables (t1 and t2) are already registered?
Thanks.
(+) is the old Oracle outer join operator. It was used like this (Scott's sample schema; there are no employees in department 40 so - if you want to display it, you have to use outer join):
SQL> select d.deptno, d.dname, e.ename
2 from emp e,
3 dept d
4 where d.deptno = e.deptno (+) --> outer join
5 order by d.deptno, e.ename;
DEPTNO DNAME ENAME
---------- -------------- ----------
10 ACCOUNTING CLARK
10 ACCOUNTING KING
10 ACCOUNTING MILLER
20 RESEARCH ADAMS
20 RESEARCH FORD
20 RESEARCH JONES
20 RESEARCH SCOTT
20 RESEARCH SMITH
30 SALES ALLEN
30 SALES BLAKE
30 SALES JAMES
30 SALES MARTIN
30 SALES TURNER
30 SALES WARD
40 OPERATIONS --> department with no employees
15 rows selected.
If Spark SQL supports modern ANSI syntax, then the above code can be rewritten to
SQL> select d.deptno, d.dname, e.ename
2 from dept d left join emp e on e.deptno = d.deptno --> outer join
3 order by d.deptno, e.ename;
DEPTNO DNAME ENAME
---------- -------------- ----------
10 ACCOUNTING CLARK
10 ACCOUNTING KING
10 ACCOUNTING MILLER
20 RESEARCH ADAMS
20 RESEARCH FORD
20 RESEARCH JONES
20 RESEARCH SCOTT
20 RESEARCH SMITH
30 SALES ALLEN
30 SALES BLAKE
30 SALES JAMES
30 SALES MARTIN
30 SALES TURNER
30 SALES WARD
40 OPERATIONS --> department with no employees
15 rows selected.
SQL>
See if it helps.
I do not see the point of joining t1 and t2:
SELECT
t1.col1,
t1.col2
FROM
t1
WHERE
t1.col1 <> 121

Oracle: Overwrite values in a column with the longest string

I’m running into a problem.
Say, I have columns called “C1, C2, C3....” in a table. I’d like to use the longest string in C1 to replace every other cells in C1 column without disturbing other columns.
I tired several ways but I cannot get my Oracle code run. Could someone please show me a sample code to do this problem? I typed my question using a cellphone so I apologize for not showing you my code. But I think my description is fine... Thank you!
I would use window functions. Oracle has a very convenient functionality with keep:
select max(col1) keep (dense_rank first order by len(col1) desc) over () as col1,
col2, col3, . . .
from t;
You can incorporate this into an update:
update t
set col1 = (select select max(col1) keep (dense_rank first order by len(col1) desc) over () as col1
from t
);
For example:
SQL> select * from test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> update test set
2 dname = (select max(dname) --> MAX fixes TOO-MANY-ROWS because ACCOUNTING
3 from test -- and OPERATIONS have same length
4 where length(dname) = (select max(length(dname))
5 from test
6 )
7 );
4 rows updated.
SQL> select * from test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 OPERATIONS NEW YORK
20 OPERATIONS DALLAS
30 OPERATIONS CHICAGO
40 OPERATIONS BOSTON
SQL>
[EDIT, GROUP BY]
Another example is based on a different table, which reflects what you described in a comment. The DEPTNO (department number) is used to "group" employees, and I'm going to update the JOB column value to the longest job name within that department.
Query is similar to the previous one; it just joins appropriate columns (DEPTNO) throughout code.
Sample data:
SQL> select * from test order by deptno, ename;
DEPTNO ENAME JOB
---------- ---------- ---------
10 CLARK MANAGER
KING PRESIDENT --> the longest in DEPTNO = 10
MILLER CLERK
20 ADAMS CLERK
FORD ANALYST
JONES MANAGER --> as long as ANALYST, but MAX(JOB) will return this value
SCOTT ANALYST
SMITH CLERK
30 ALLEN SALESMAN --> the longest in DEPTNO = 30
BLAKE MANAGER
JAMES CLERK
MARTIN SALESMAN
TURNER SALESMAN
WARD SALESMAN
Update and the result:
SQL> update test t set
2 t.job = (select max(t1.job)
3 from test t1
4 where t1.deptno = t.deptno
5 and length(t1.job) = (select max(length(t2.job))
6 from test t2
7 where t2.deptno = t1.deptno
8 )
9 );
14 rows updated.
SQL> select * from test order by deptno, ename;
DEPTNO ENAME JOB
---------- ---------- ---------
10 CLARK PRESIDENT
KING PRESIDENT
MILLER PRESIDENT
20 ADAMS MANAGER
FORD MANAGER
JONES MANAGER
SCOTT MANAGER
SMITH MANAGER
30 ALLEN SALESMAN
BLAKE SALESMAN
JAMES SALESMAN
MARTIN SALESMAN
TURNER SALESMAN
WARD SALESMAN

SQL Select query gave a duplicate results

I'm working with the two Oracle example tables, Emp and Dept.
I made this query:
SELECT ENAME,DNAME,LOC FROM EMP INNER JOIN DEPT ON EMP.DEPTNO = 10.
The number 10 is the dept id in the Dept table. I just want to retrieve the records with the deptid 10. The query works but it gave me duplicated records.
Here are the results:
ENAME DNAME LOC DEPTNO
========= ========== ======== ======
JAMES ACCOUNTING NEW YORK 10
CLARK KEN ACCOUNTING NEW YORK 10
JAMES RESEARCH DALLAS 20
CLARK KEN RESEARCH DALLAS 20
JAMES SALES CHICAGO 30
CLARK KEN SALES CHICAGO 30
JAMES OPERATIONS BOSTON 40
CLARK KEN OPERATIONS BOSTON 40
As you can see, the first two records match the query and the same records are duplicated.
You need to change the on criteria and then add where criteria instead:
SELECT ENAME,DNAME,LOC
FROM EMP
INNER JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO
WHERE DEPT.DEPTNO = 10
You have no where clause.
SELECT ENAME,DNAME,LOC FROM EMP WHERE DEPTNO = 10