SQL: Find max number of rows - sql
I am totally new to coding so might be my question is silly sorry about it first.
I have a database that has CUST_REFERRED represent CUST_NUMBER who referred book someone
CUST_NUM NAME_S NAME_F ADDRESS Z_CODE CUST_REFERRED
1001 MORALES BONITA P.O. BOX 651 32328
1002 THOMPSON RYAN P.O. BOX 9835 90404
1003 SMITH LEILA P.O. BOX 66 32306
1004 PIERSON THOMAS 69821 SOUTH AVENUE 83707
1005 GIRARD CINDY P.O. BOX 851 98115
1006 CRUZ MESHIA 82 DIRT ROAD 12211
1007 GIANA TAMMY 9153 MAIN STREET 78710 1003
1008 JONES KENNETH P.O. BOX 137 82003
1009 PEREZ JORGE P.O. BOX 8564 91510 1003
1010 LUCAS JAKE 114 EAST SAVANNAH 30314
1011 MCGOVERN REESE P.O. BOX 18 60606
1012 MCKENZIE WILLIAM P.O. BOX 971 02110
1013 NGUYEN NICHOLAS 357 WHITE EAGLE AVE 34711 1006
1014 LEE JASMINE P.O. BOX 2947 82414
1015 SCHELL STEVE P.O. BOX 677 33111
1016 DAUM MICHELL 9851231 LONG ROAD 91508 1010
1017 NELSON BECCA P.O. BOX 563 49006
1018 MONTIASA GREG 1008 GRAND AVENUE 31206
1019 SMITH JENNIFER P.O. BOX 1151 07962 1003
1020 FALAH KENNETH P.O. BOX 335 08607
My idea is to find customer who referred max book. So as you can see 3 times 1003 number referred book who name is LEILA SMITH
I tried a code that;
SELECT
CUST_REFERRED,
COUNT(*)
FROM
CUSTOMER
GROUP BY
CUST_REFERRED
ORDER BY CUST_REFERRED ASC;
This code gives me:
1003 3
1006 1
1010 1
First, my question is I could not use LIMIT function to find max number
and the second question is How Can I add more information of customer?
SELECT NAME_F,
NAME_S,
ADDRESS,
CUST_REFERRED
FROM CUSTOMER
WHERE CUST_NUM = (SELECT MOST_CUS_REF
FROM (SELECT CUST_REFERRED MOST_CUS_REF, COUNT(CUST_REFERRED)
MOST_CUS_REF_COUNT
FROM (SELECT CUST_REFERRED
FROM customer
WHERE cust_referred IS NOT NULL
)
GROUP BY CUST_REFERRED
HAVING COUNT(CUST_REFERRED) = (SELECT MAX (cust_ref_num)
FROM (SELECT CUST_REFERRED,
COUNT(CUST_REFERRED) cust_ref_num
FROM (SELECT CUST_REFERRED
FROM customer
WHERE cust_referred IS NOT NULL
)
GROUP BY CUST_REFERRED
)
)
)
)
;
try this:
Select CUST_REFERRED, z.cnt from
(SELECT CUST_REFERRED, COUNT(*) cnt
FROM CUSTOMER where CUST_REFERRED is Not null
GROUP BY CUST_REFERRED) Z
where z.cnt =
(select Max(cnt) from
(SELECT COUNT(*) cnt
FROM CUSTOMER where CUST_REFERRED is Not null
GROUP BY CUST_REFERRED) ZZ)
Try this query --
;WITH CTE
AS (
SELECT CUSTOMER_REFID COUNT(*) AS REF_COUNT
FROM CUSTOMER
GROUP BY CUSTOMER_REFID
)
SELECT TOP 1 C2.CUSTOMER_ID
,C2.FIRST_NAME
,C2.LAST_NAME
,REF_COUNT
FROM CTE C1
INNER JOIN CUSTOMER C2
ON C1.CUSTOMER_REFID = C2.CUSTOMER_ID
ORDER BY REF_COUNT DESC
edited to add the referred customer details.
with data (cust_num, name_s, name_f, addr, code, cust_referred) as
(
/* begin: test data */
select 1001 ,'MORALES ','BONITA ','P.O. BOX 651 ',32328, null from dual union all
select 1002 ,'THOMPSON ','RYAN ','P.O. BOX 9835 ',90404, null from dual union all
select 1003 ,'SMITH ','LEILA ','P.O. BOX 66 ',32306, null from dual union all
select 1004 ,'PIERSON ','THOMAS ','69821, SOUTH AVENUE ',83707, null from dual union all
select 1005 ,'GIRARD ','CINDY ','P.O. BOX 851 ',98115, null from dual union all
select 1006 ,'CRUZ ','MESHIA ','82 DIRT ROAD ',12211, null from dual union all
select 1007 ,'GIANA ','TAMMY ','9153 MAIN STREET ',78710, 1003 from dual union all
select 1008 ,'JONES ','KENNETH ','P.O. BOX 137 ',82003, null from dual union all
select 1009 ,'PEREZ ','JORGE ','P.O. BOX 8564 ',91510, 1003 from dual union all
select 1010 ,'LUCAS ','JAKE ','114 EAST SAVANNAH ',30314, null from dual union all
select 1011 ,'MCGOVERN ','REESE ','P.O. BOX 18 ',60606, null from dual union all
select 1012 ,'MCKENZIE ','WILLIAM ','P.O. BOX 971 ',02110, null from dual union all
select 1013 ,'NGUYEN ','NICHOLAS ','357 WHITE EAGLE AVE ',34711, 1006 from dual union all
select 1014 ,'LEE ','JASMINE ','P.O. BOX 2947 ',82414, null from dual union all
select 1015 ,'SCHELL ','STEVE ','P.O. BOX 677 ',33111, null from dual union all
select 1016 ,'DAUM ','MICHELL ',',9851231, LONG ROAD ',91508, 1010 from dual union all
select 1017 ,'NELSON ','BECCA ','P.O. BOX 563 ',49006, null from dual union all
select 1018 ,'MONTIASA ','GREG ','1008 GRAND AVENUE ',31206, null from dual union all
select 1019 ,'SMITH ','JENNIFER ','P.O. BOX 1151 ',07962, 1003 from dual union all
select 1020 ,'FALAH ','KENNETH ','P.O. BOX 335 ',08607, null from dual
/* end: test data */
-- replace the above block with your table
-- eg. select * from customers_table
)
,
max_referred as
(
-- just interested in the first row after sorting by
-- the count of referred column values
select rownum, cust_referred, cnt from
(
select cust_referred, count(cust_referred) cnt from data group by cust_referred order by 2 desc
)
where rownum = 1
)
-- joining on cust_referred column in *data* and *max_referred* tables to get the customer details
-- and joining again to the *data* table for fetching the referred customer name
select
cust.cust_num, cust.name_s, cust.name_f, cust.addr, cust.code, cust.cust_referred, ms.name_f || ms.name_s as "Referred Customer"
from
data cust
join
max_referred mr on (cust.cust_referred = mr.cust_referred)
join
data ms
on (mr.cust_referred = ms.cust_num)
;
You can do it in a single table scan (i.e. without any self joins) using analytic functions:
SELECT *
FROM (
SELECT t.*,
MIN( CUST_REFERRED )
KEEP ( DENSE_RANK FIRST ORDER BY num_referrals DESC )
OVER ()
AS best_referrer
FROM (
SELECT c.*,
COUNT( CUST_REFERRED )
OVER ( PARTITION BY CUST_REFERRED )
AS num_referrals
FROM CUSTOMER c
) t
)
WHERE cust_num = best_referrer;
Related
SQL needed to find if a property exists in multiple counties
I need some SQL to determine if a property exists in multiple counties. I have a list of distinct property ids and county ids, but I'm not sure how to find if the property exists in more than one county. TABLE: PROPERTIES PROPERTYID COUNTYID 12345 1111 12345 1112 23456 1111 34567 2222 In this example, I need some sql that will only show me property 12345 since it exists in both county 1111 and 1112. I'm sure there is some easy SQL, but I can't figure it out.
Sample data: SQL> with properties (propertyid, countryid) as 2 (select 12345, 1111 from dual union all 3 select 12345, 1112 from dual union all 4 select 23456, 1111 from dual union all 5 select 34567, 2222 from dual 6 ) Query: 7 select propertyid 8 from properties 9 group by propertyid 10 having count(distinct countryid) > 1; PROPERTYID ---------- 12345 SQL>
Find the discrepancies in sql
I am using Oracle database. Suppose that I have a table called "MYTABLE" and it contains the tuples of every dog in the world and the owners: NAME OWNER_ID Aaron 81 Aaron 281 Aaron 404 Michael 81 Michael 281 Michael 404 Brendan 281 Brendan 81 Micon 404 Micon 81 Tyson 404 For DEFAULT every DOG must be associated with 3 different owners, in this case the owners are identified by an id: 81, 281 and 404. How can I know the dogs that are not associated with 3 rows in the table? I would like this output: Brendan Micon Tyson These 3 dogs do not have 3 rows in the given table. They are not associated exactly with owners 81, 281 and 404.
To find out which name is not associated with all three of the 81, 281 and 404 owner_id, you can use conditional aggregation in a HAVING clause: SELECT name FROM table_name GROUP BY name HAVING COUNT(DISTINCT CASE WHEN OWNER_ID IN (81, 281, 404) THEN OWNER_ID END) < 3 Which, for the sample data: CREATE TABLE table_name (NAME, OWNER_ID) AS SELECT 'Aaron', 81 FROM DUAL UNION ALL SELECT 'Aaron', 281 FROM DUAL UNION ALL SELECT 'Aaron', 404 FROM DUAL UNION ALL SELECT 'Michael', 81 FROM DUAL UNION ALL SELECT 'Michael', 281 FROM DUAL UNION ALL SELECT 'Michael', 404 FROM DUAL UNION ALL SELECT 'Brendan', 281 FROM DUAL UNION ALL SELECT 'Brendan', 81 FROM DUAL UNION ALL SELECT 'Brendan', 123 FROM DUAL UNION ALL -- Different owner_id SELECT 'Micon', 404 FROM DUAL UNION ALL SELECT 'Micon', 81 FROM DUAL UNION ALL SELECT 'Micon', 81 FROM DUAL UNION ALL -- Duplicate SELECT 'Tyson', 404 FROM DUAL Outputs: NAME Brendan Micon Tyson If you just want the name where they do not have three different owner_id (any owner_id) then: SELECT name FROM table_name GROUP BY name HAVING COUNT(DISTINCT OWNER_ID) < 3 Which, for the same sample data, would output: NAME Micon Tyson If you just want the name where there are not three owner_id (either unique or not) then: SELECT name FROM table_name GROUP BY name HAVING COUNT(OWNER_ID) < 3 Which, for the same sample data, outputs: NAME Tyson db<>fiddle here
You can GROUP BY the NAME and the use COUNT(*) to exclude al that have less than 3 owners SELECT "NAME" FROM tab1 GROUP BY "NAME" HAVING COUNT(*) < 3 | NAME | | :------ | | Brendan | | Micon | | Tyson | db<>fiddle here
How to optimise SQL query without using NOT IN
I have this Student table: Id companyId status ---------------------------------------- 101 1001 In-Progress 102 1001 In-Progress 103 1001 Final 104 1002 In-Progress 105 1003 Pending With Company 106 1003 In-Progress 107 1004 In-Progress 108 1004 In-Progress 109 1005 In-Progress 110 1005 Completed 111 1006 In-Progress 112 1006 Canceled 113 1007 In-Progress 114 1007 Pending with Student I want output with these conditions: Status is "In-Progress" If have repeated companyId then other allowed staus is Completed, Canceled (Basically only allowed combination of the staus is In-Progress, Completed and Canceled) With above condition o/p will look like this: Id companyId status -------------------------------- 104 1002 In-Progress 107 1004 In-Progress 108 1004 In-Progress 109 1005 In-Progress 111 1006 In-Progress We can achieve this by using NOT IN SELECT * FROM student WHERE status = 'In-Progress' AND companyId NOT IN (SELECT companyId FROM student WHERE status IN ('Final', 'Pending With Company ', 'Pending with Student')); But I'm looking for a solution without using NOT IN.
You can use not exists SELECT * FROM student a WHERE a.status = 'In-Progress' AND NOT EXISTS (SELECT null FROM student b WHERE a.companyid=b.companyid AND b.status not in ('In progress','Completed','Cancelled') )
you can achieve it using left join and choosing not match rows: SELECT * FROM student a LEFT JOIN ( SELECT companyId FROM student WHERE status in ('Final','Pending With Company ','Pending with Student')) b on a.companyid=b.companyId where b.companyId is null and a.status = 'In-Progress'
WITH status as ( select 1 as s,'In-Progress' d union all select 100 as s,'Final' d union all select 100 as s,'Pending With Company' d union all select 100 as s,'Pending with Student' d union all select 1 as s,'Cancelled' d union all select 1 as s,'Completed' ) SELECT * FROM ( SELECT s.Id, s.CompanyID, s.status, MAX(status.s) OVER (partition by s.CompanyId) m FROM student s LEFT jOIN status ON s.status = status.d ) x where x.m=1 and x.status='In-Progress' Remember, above is simply not using NOT IN. Discussion about this query not being performant is different.
SQL output formatted in one line per entry
I have a problem getting data displayed right, directly from Oracle SQL. I have 2 tables. Medarb with entries meda_id and init and contacts with meda_id, cont_type and number. The cont_type can be either 'MT' or 'MA' what I get is: init type number aaaa MT 11111111 aaaa MA 22222222 bbbb MT 33333333 bbbb MA 44444444 and so on. what I wanted was: (each person on one line) aaaa mt 11111111 ma 22222222 bbbb mt 33333333 ma 44444444 and so on. Is that possible? The SQL is like this: select distinct medarb.init, contacts.cont_type, contacts.number from contacts inner join medarb on medarb.meda_id = contacts.meda_id order by medarb.init Kind regards Per
Aggregation usually helps in such situations. SQL> with test (init, type, cnumber) as 2 (select 'aaaa', 'MT', 111 from dual union all 3 select 'aaaa', 'MA', 222 from dual union all 4 select 'bbbb', 'MT', 333 from dual union all 5 select 'bbbb', 'MA', 444 from dual 6 ) 7 select init, 8 'MT' mttype, 9 max(case when type = 'MT' then cnumber end) cnum_mt, 10 'MA' matype, 11 max(case when type = 'MA' then cnumber end) cnum_ma 12 from test 13 group by init 14 order by init; INIT MT CNUM_MT MA CNUM_MA ---- -- ---------- -- ---------- aaaa MT 111 MA 222 bbbb MT 333 MA 444 SQL>
what is the unique column combination for this join, is it init and type columns? You can try using Oracle Pivot functions. https://blogs.oracle.com/sql/how-to-convert-rows-to-columns-and-back-again-with-sql-aka-pivot-and-unpivot thanks
SQL getting multiple rows in PARTICULAR sql
I have a table abc with following rows: emp_id_role Group_name Role_name Location_id 12 Insurance Manager Noida 12 Insurance Senior Manager Noida 13 Global Client Services Sw UP 14 Operations Management All Jobs kERALA and another master table with all the details employee_xyz: PERSON_ID NAME DOB START_DATE END_DATE SSN 12 DEAN 01-JAN-1990 01-JAN-2017 20-JAN-2017 847474 12 DEAN 01-JAN-1990 21-JAN-2017 03-mar-2018 847474 12 DEAN 01-JAN-1990 04-mar2018 31-DEC-4712 847474 13 SAM 20-JAN-1990 17-JAN-2016 20-JAN-2017 847474 13 SAM 20-JAN-1990 21-JAN-2017 31-DEC-4712 847474 14 JAY 29-dec-1990 21-JAN-2016 31-DEC-4712 847474 I want to fetch the full names from the table employee_xyz for the records in table abc. When I'm joining these two using the below queries I'm getting more number of rows for an employee than in table abc, Eg: for employee_id 12 I should get 2 rows as in table abc but I'm getting 9 rows somehow... Query used is simple : select * from table_abc abc, employee_xyz xyz where xyz.person_id=abc.emp_id_role and trunc(sysdate) between abc.Start_date and xyz.end_date and person_id=12;
I suppose you want to select all columns from table_abc with names from employee_xyz. If your try with select abc.*, xyz.name, you already able to select as two rows since sysdate for person_id= 12 stays in the interval only for third row(start_date:04-mar2018/ end_date:31-DEC-4712) but if you want non-repeating even with more date values stay, you can use distinct : select distinct abc.*, xyz.name as below( where there're two rows in the interval second row's end date converted from '2018-03-03' to '2019-03-03' ) : with table_abc(emp_id_role, Group_name, Role_name, Location_id) as ( select 12,'Insurance','Manager','Noida' from dual union all select 12,'Insurance','Senior Manager','Noida' from dual union all select 13,'Global Client Services','Sw', 'UP' from dual union all select 14,'Operations Management','All Jobs','kERALA' from dual ), employee_xyz(person_id,name, dob, start_date, end_date, ssn) as ( select 12,'DEAN',date'1990-01-01',date'2017-01-01',date'2017-01-20',847474 from dual union all select 12,'DEAN',date'1990-01-01',date'2017-01-21',date'2019-03-03',847474 from dual union all select 12,'DEAN',date'1990-01-01',date'2018-03-04',date'4712-12-31',847474 from dual ) select distinct abc.*, xyz.name from table_abc abc join employee_xyz xyz on xyz.person_id = abc.emp_id_role where trunc(sysdate) between xyz.Start_date and xyz.end_date and person_id = 12; EMP_ID_ROLE GROUP_NAME ROLE_NAME LOCATION_ID NAME ----------- ---------- --------------- ----------- ----- 12 Insurance Manager Noida DEAN 12 Insurance Senior Manager Noida DEAN