Count duplicate numbers in postgres - count

i have quick question.
I would like to count rows with same number.
This is what i get:
So i have 4 rows, with same number(59 b) and in count column i get ones.
I need to get 4 instead of 1, becouse i have 4 rows with same number.
This is my sql:
SELECT (z.miasto ||' '|| z.ulica ||' '|| z.nr_dom) as adres, (z.sym ||z.sym_ul||' '|| z.nr_dom) as symbol, zd.status, zd.id_administrator, z.uwagi,
COUNT(*) as liczba_osob
FROM zgloszenia as z
LEFT JOIN zgl_dzialamy AS zd ON (z.sym ||z.sym_ul||' '|| z.nr_dom) = (zd.sym ||zd.sym_ul||' '|| zd.nr_budynku)
WHERE status < 5
group by adres, symbol, zd.id_administrator, z.uwagi, zd.status
Can somebody tell me what am I doing wrong?

The reason why COUNT doesnt work is because the grouped values cannot aggregate.
They appear to be distinct from each other (probably the blacked out value: z.uwagi).
What you can do is SELECTing the non-DISTINCT values together and COUNT those instead. You can join this VALUE to your table after once the COUNTing is done. Or you can aggregate this column to your table as an array or json object.
SELECT
(z.miasto ||' '|| z.ulica ||' '|| z.nr_dom) as adres,
(z.sym ||z.sym_ul||' '|| z.nr_dom) as symbol,
zd.status,
zd.id_administrator,
-- z.uwagi, -- VALUE IS DISTINCT
COUNT(*) as liczba_osob
FROM zgloszenia as z
LEFT JOIN zgl_dzialamy AS zd ON (z.sym ||z.sym_ul||' '|| z.nr_dom) = (zd.sym ||zd.sym_ul||' '|| zd.nr_budynku)
WHERE status < 5
group by
adres,
symbol,
zd.id_administrator,
-- z.uwagi,
zd.status

Related

Need to delete all tables based on their references i.e FK and PK

I need to create a script to clean up all the objects in the schema 'myschema'.
Order will be like
All tables(FK PK order)
How do I achieve this in one PLSQL block.
set serveroutput on;
declare
lv_str varchar2(1000);
begin
for c in(select distinct a.table_name as table_name, b.table_name as parent_table_name
from
all_constraints a
left outer join all_constraints b on a.r_constraint_name = b.constraint_name and a.owner = b.owner) loop
lv_str :='DROP TABLE '||c.table_name;
--lv_str :='DROP TABLE '||c.parent_table_name;
dbms_output.put_line(lv_str);
end loop;
end;
This is a script I use to clear Scott's schema. Why? I use it for testing purposes and, as time goes by, it turns into a mess. I don't pay much attention about what I remove and in which order; I simply run it 2-3 times and everything's gone. See if you can use it, improve it if you want.
SET SERVEROUTPUT ON;
DECLARE
l_user VARCHAR2 (30) := 'SCOTT';
l_str VARCHAR2 (200);
BEGIN
IF USER = l_user
THEN
FOR cur_r IN (SELECT object_name, object_type
FROM user_objects
WHERE object_name NOT IN ('EMP',
'DEPT',
'BONUS',
'SALGRADE'))
LOOP
BEGIN
l_str :=
'drop '
|| cur_r.object_type
|| ' "'
|| cur_r.object_name
|| '"';
DBMS_OUTPUT.put_line (l_str);
EXECUTE IMMEDIATE l_str;
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
END LOOP;
END IF;
END;
/
PURGE RECYCLEBIN;
SELECT * FROM user_objects;
How to drop foreign key constraints first, and then drop tables:
SQL> set serveroutput on
SQL> declare
2 l_str varchar2(200);
3 begin
4 for cur_r in (select table_name, constraint_name
5 from user_constraints
6 where constraint_type = 'R')
7 loop
8 l_str := 'alter table ' || cur_r.table_name ||
9 ' drop constraint ' || cur_r.constraint_name;
10 dbms_output.put_line(l_str);
11
12 execute immediate l_str;
13 end loop;
14
15 --
16
17 for cur_r in (select table_name from user_tables where table_name not in ('EMP', 'DEPT'))
18 loop
19 l_str := 'drop table ' || cur_r.table_name;
20
21 dbms_output.put_line(l_str);
22
23 execute immediate l_str;
24 end loop;
25 end;
26 /
alter table TDET drop constraint SYS_C00105662
drop table BONUS
drop table SALGRADE
drop table TEST
drop table MYTABLE
drop table TABLEB
drop table TABLEA
drop table EMPLOYEES
drop table T_PRINT
drop table TMAS
drop table TDET
PL/SQL procedure successfully completed.
SQL>

Update in PL/SQL Block giving PLS-00103 error

I am trying to create a PL/SQL block to update a empty column, is_true, in a new table created_table on the basis of another table, table1. The id fields on the tables match and there are no rows in created_table that doesn't have a corresponding row in table1. I'm basing the update on the status column of table1, but instead of 'Yes' and 'No', I need it reflected as 'Y' and 'N':
created_table: expected results:
id | is_true | other columns id | is_true | other columns
---|---------|-------------- ---|---------|--------------
1 | null | ... 1 | 'Y' | ...
2 | null | ... 2 | 'N' | ...
table1:
id | status | other columns
---|--------|--------------
1 | 'Yes' | ...
2 | 'No' | ...
Since created_table is very large, I'm trying to update it using a PL/SQL procedure, so that in case of failure midway, I'll still have updated rows. The next run of the procedure can then pick up where it previously failed without processing already processed rows.
I've tried testing with this code block:
DECLARE
is_true varchar2 (5) created_table.is_true%type;
BEGIN
FOR status IN (SELECT a.status
from table1 a
left join created_table b
where and a.id=b.id )
LOOP
IF status = 'Yes' THEN
UPDATE created_table SET is_true= 'Y'
ELSE
UPDATE created_table SET is_true= 'N'
WHERE ROWNUM := status.ROWNUM
END IF;
DBMS_OUTPUT.PUT_LINE('Done');
END LOOP;
END;
But it's giving me errors:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem
What can I do to make it work?
Your code had multiple errors:
DECLARE
-- is_true varchar2 (5) created_table.is_true%type; -- PLS-00103: Encountered the symbol "CREATED_TABLE" when expecting one of the following:
is_true created_table.is_true%type;
BEGIN
FOR status IN (SELECT a.status
from table1 a
-- left join created_table b -- ORA-00905: missing keyword
-- where and a.id=b.id )
left join created_table b on a.id = b.id)
LOOP
-- IF status = 'Yes' THEN -- PLS-00306: wrong number or types of arguments in call to '='
IF status.status = 'Yes' THEN
-- UPDATE created_table SET is_true= 'Y' -- ORA-00933: SQL command not properly ended
UPDATE created_table SET is_true= 'Y';
ELSE
UPDATE created_table SET is_true= 'N'
-- WHERE ROWNUM := status.ROWNUM -- ORA-00920: invalid relational operator and ORA-00933: SQL command not properly ended
WHERE ROWNUM = status.ROWNUM;
END IF;
DBMS_OUTPUT.PUT_LINE('Done');
END LOOP;
END; -- PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
/
The PLS-00103 is really just telling you that a / is missing. After that the remaining error is PLS-00302: component 'ROWNUM' must be declared. From "Oracle Database Online Documentation": rownum is a pseudocolumn.
Your SQL would update every row in the table setting is_true to 'Y' on the first encounter of status being 'Yes', since you didn't give it a WHERE clause. I'm assuming that is not your intent.
There was also no COMMIT in your PL/SQL block, so in effect it would have been the same as running a normal SQL.
Based on the situation you've described, I made some changes to the code block. This will provide with a limit for how many rows can be processed prior to a COMMIT. I set the limit to 5. You should change that to something appropriate. It will not pick up any rows that have empty values for is_true, so in effect it will only work on non-processed rows:
DECLARE
commit_counter PLS_INTEGER := 1; -- count commits
commit_limit PLS_INTEGER := 5; -- rows for commit limit
counter PLS_INTEGER := commit_limit;
BEGIN
FOR rec IN (SELECT a.status, a.id
FROM created_table b
JOIN table1 a ON a.id = b.id
WHERE b.is_true IS NULL) -- do not pick up processed rows
LOOP
IF rec.status = 'Yes' THEN
UPDATE created_table SET is_true = 'Y'
WHERE id = rec.id;
ELSE
UPDATE created_table SET is_true = 'N'
WHERE id = rec.id;
END IF;
counter := counter - 1;
IF counter < 1 THEN
counter := commit_limit; --reset counter
commit_counter := commit_counter + 1;
COMMIT;
END IF;
END LOOP;
COMMIT; -- all rows are processed;
DBMS_OUTPUT.PUT_LINE(commit_counter || ' COMMITS');
END;
/
This will update all the rows in one go, still only updating the "empty" rows:
UPDATE created_table b
SET is_true = (SELECT CASE a.status WHEN 'Yes' THEN 'Y'
ELSE 'N'
END
FROM table1 a
WHERE a.id = b.id)
WHERE b.is_true IS NULL;

Use cursor in LOOP in new QUERY

"I missing the forest through the trees..."
I want to query each column of a table which I retrieve in a FOR LOOP, but the inner query doesn't return the right thing.
Seems that the inner query not use the current column_name.
DECLARE
v_max_TS TIMESTAMP;
BEGIN
FOR cols IN (SELECT column_name FROM all_tab_cols WHERE table_name = '<tablename>')
LOOP
SELECT
MAX(CURR_TIMESTAMP) INTO v_max_TS
FROM <tablename>
WHERE cols.column_name IS NOT NULL
ORDER BY TO_TIMESTAMP(CURR_TIMESTAMP,'MM/DD/YYYY HH24:MI:SS') DESC;
dbms_output.put_line(cols.column_name || ' ' || v_max_TS);
END LOOP;
END;
Apart from the fact that your query doesn't make much sense (as Boneist wrote as a comment), that won't work as you need to use dynamic SQL (execute immediate) for such a purpose.
Here's an example based on Scott's schema. Have a look, adjust it if necessary.
SQL> set serveroutput on
SQL> declare
2 l_str varchar2(200); -- will hold the SELECT statement
3 v_max varchar2(30);
4 begin
5 for cols in (select column_name
6 from all_tab_cols
7 where table_name = 'DEPT'
8 )
9 loop
10 l_str := 'select max(' || cols.column_name ||') from dept';
11 execute immediate l_str into v_max;
12 dbms_output.put_line(cols.column_name ||': '|| v_max);
13 end loop;
14 end;
15 /
DEPTNO: 40
DNAME: SALES
LOC: NEW YORK
PL/SQL procedure successfully completed.
SQL>

Total Number and Total Value pl/sql

I made a query within a cursor that calculates the total number of cancellations, cancels or returned items and the total value. However, I cannot get the right value for the totals of the items that been cancelled, return or all cancelled
create or replace PROCEDURE NUM_OF_RET_CAN(PRAM_DATE IN DATE)
AS
CURSOR CUR2 IS
SELECT I.CONDITION, I.DEL_DATE, SUM(DE.QUANTITY) NUMBER_OF_PRO,
SUM(NVL(DE.QUANTITY,0) * NVL (P.COSTS,0)) TOTAL
FROM ITEMS I, DE_DETAILS DE, PARTS P
WHERE DE.PRO_NO = P.PRO_NO
AND I.ITEMS_NO = DE.ITEM_NO
AND TO_CHAR(I.DEL_DATE, 'mm-yyyy') = TO_CHAR(PRAM_DATE, 'mm-yyyy')
GROUP BY I.CONDITION, I.DEL_DATE;
CAL_CUR CUR2%ROWTYPE;
BEGIN
OPEN CUR2;
FETCH CUR2 INTO CAL_CUR;
IF VARCUR1.CONDITION ='CANCELL' THEN
DBMS_OUTPUT.PUT_LINE('CANCELLED: '||CAL_CUR.NUMBER_OF_PRO );
DBMS_OUTPUT.PUT_LINE('Total: '|| CAL_CUR.TOTAL);
ELSIF VARCUR1.CONDITION ='ORDER RETURNED' THEN
DBMS_OUTPUT.PUT_LINE('RETURNED : '||
CAL_CUR.NUMBER_OF_PRO);
DBMS_OUTPUT.PUT_LINE('Total : '|| CAL_CUR.TOTAL);
ELSIF VARCUR1.CONDITION = 'ALL ORDERS ARE CANCELLED!' THEN
DBMS_OUTPUT.PUT_LINE('ALL CANCELLATIONS : '||
CAL_CUR.NUMBER_OF_PRO );
DBMS_OUTPUT.PUT_LINE('Total : '|| CAL_CUR.TOTAL);
ELSE
DBMS_OUTPUT.PUT_LINE('No records for this month');
END IF;
CLOSE CUR2;
END NUM_OF_RET_CAN;
If I run the select Query without using the cursor or the procedure I get this result:
CONDITION DEL_DATE NUMBER_OF_PRO TOTAL
------------ ------------- ------------------- ---------
ALL ORDERS ARE CANCELLED! 12-JAN-16 4 99.96
ALL ORDERS ARE CANCELLED! 10-JAN-16 2 44.98
Expected Answer
CONDITION DEL_DATE NUMBER_OF_PRO TOTAL
------------ ------------- ------------------- ---------
ALL ORDERS ARE CANCELLED! JAN-16 6 144.94
Any help would be much appreciated
Sounds like you just need to group by month rather than day, eg:
select i.condition,
trunc(i.del_date, 'mm') del_date,
sum(de.quantity) number_of_pro,
sum(nvl(de.quantity,0) * nvl (p.costs,0)) total
from items i
inner join de_details de on (i.items_no = de.item_no)
inner join parts p on (de.pro_no = p.pro_no)
where trunc(i.del_date, 'mm') = trunc(pram_date, 'mm')
group by i.condition,
trunc(i.del_date, 'mm');
A few notes:
You'll note that I have converted your old-style joins into ANSI join syntax.
You had aliased the items table as "pros" but elsewhere in the query, the alias "i" was referenced. I believe this is what the alias for the items table should have been, so I updated it accordingly.
I've converted your to_char(... 'mm-yyyy')s to trunc(... 'mm') as I believe that comparing columns in the same format as they're defined is more meaningful (leading to easier maintenance etc).
I'm not sure why you're getting the "not a group by expression" error, since it's working for me:
with items as (select 1 items_no, 'a' condition, sysdate -1 del_date from dual union all
select 2 items_no, 'a' condition, sysdate del_date from dual union all
select 3 items_no, 'a' condition, sysdate + 31 del_date from dual),
de_details as (select 1 item_no, 10 quantity, 1 pro_no from dual union all
select 2 item_no, 20 quantity, 2 pro_no from dual union all
select 3 item_no, 40 quantity, 1 pro_no from dual),
parts as (select 1 pro_no, 100 costs from dual union all
select 2 pro_no, 200 costs from dual)
----- end of mimicking your tables with data in them
select i.condition,
trunc(i.del_date, 'mm') del_date,
sum(de.quantity) number_of_pro,
sum(nvl(de.quantity,0) * nvl (p.costs,0)) total
from items i
inner join de_details de on (i.items_no = de.item_no)
inner join parts p on (de.pro_no = p.pro_no)
--where trunc(i.del_date, 'mm') = trunc(pram_date, 'mm')
group by i.condition,
trunc(i.del_date, 'mm');
CONDITION DEL_DATE NUMBER_OF_PRO TOTAL
--------- --------- ------------- ----------
a 01-JAN-16 30 5000
a 01-FEB-16 40 4000
Are you sure that you added the trunc(..., 'mm') to the colunn in both the select and group by colunn lists?
Here's how I'd write the procedure, assuming that I needed to loop through each of the rows returned by the query and display them via dbms_output:
create or replace procedure num_of_ret_can (pram_date in date)
as
cursor cur2 is
select i.condition,
trunc(i.del_date, 'mm') del_date,
sum(de.quantity) number_of_pro,
sum(nvl(de.quantity,0) * nvl (p.costs,0)) total
from items i
inner join de_details de on (i.items_no = de.item_no)
inner join parts p on (de.pro_no = p.pro_no)
where trunc(i.del_date, 'mm') = trunc(pram_date, 'mm')
group by i.condition,
trunc(i.del_date, 'mm');
v_counter number := 0;
begin
for cal_cur in cur2
loop
v_counter := v_counter + 1;
if cal_cur.condition ='CANCELL' then -- are you sure? Not CANCEL?
dbms_output.put_line('CANCELLED: '||cal_cur.number_of_pro );
dbms_output.put_line('Total: '|| cal_cur.total);
elsif cal_cur.condition ='ORDER RETURNED' then
dbms_output.put_line('RETURNED : '||cal_cur.number_of_pro);
dbms_output.put_line('Total : '||cal_cur.total);
elsif cal_cur.condition = 'ALL ORDERS ARE CANCELLED!' then
dbms_output.put_line('ALL CANCELLATIONS : '||cal_cur.number_of_pro );
dbms_output.put_line('Total : '||cal_cur.total);
end if;
end loop;
if v_counter = 0 then
dbms_output.put_line('No records for this month');
end if;
end num_of_ret_can;
/

Pl/SQL - oracle 9i - Manual Pivoting

We have a table which has three columns in it:
Customer_name, Age_range, Number_of_people.
1 1-5 10
1 5-10 15
We need to return all the number of people in different age ranges as rows of a single query. If we search for customer #1, the query should just return one row:
Header- Age Range (1-5) Age Range (5-10)
10 15
We needed to get all the results in a single row; When I query for customer 1, the result should be only number of people in a single row group by age_range.
What would be the best way to approach this?
You need to manually perform a pivot:
SELECT SUM(CASE WHEN age_range = '5-10'
THEN number_of_people
ELSE NULL END) AS nop5,
SUM(CASE WHEN age_range = '10-15'
THEN number_of_people
ELSE NULL END) AS nop10
FROM customers
WHERE customer_name = 1;
There are easy solutions with 10g and 11g using LISTGAGG, COLLECT, or other capabilities added after 9i but I believe that the following will work in 9i.
Source (http://www.williamrobertson.net/documents/one-row.html)
You will just need to replace deptno with customer_name and ename with Number_of_people
SELECT deptno,
LTRIM(SYS_CONNECT_BY_PATH(ename,','))
FROM ( SELECT deptno,
ename,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS seq
FROM emp )
WHERE connect_by_isleaf = 1
CONNECT BY seq = PRIOR seq +1 AND deptno = PRIOR deptno
START WITH seq = 1;
DEPTNO CONCATENATED
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
3 rows selected.
This will create a stored FUNCTION which means you can access it at any time.
CREATE OR REPLACE FUNCTION number_of_people(p_customer_name VARCHAR2)
RETURN VARCHAR2
IS
v_number_of_people NUMBER;
v_result VARCHAR2(500);
CURSOR c1
IS
SELECT Number_of_people FROM the_table WHERE Customer_name = p_customer_name;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO v_number_of_people;
EXIT WHEN c1%NOTFOUND;
v_result := v_result || v_number_of_people || ' ' || CHR(13);
END;
END;
To run it, use:
SELECT number_of_people(1) INTO dual;
Hope this helps, and please let me know if there are any errors, I didn't testrun the function myself.
Just do
select Number_of_people
from table
where Customer_name = 1
Are we missing some detail?

Resources