How to hide distinct column in sql selection - sql

I am doing a query in sql to find rows with distinct value of name as below:
select distinct name, age, sex from person
it works but I don't want to show the name column in the result set. Is there a way to hide this column?
EDIT1
the reason I put distinct name there is to avoid multiple rows with the same name returned. My table has person with the same name but different age and sex. So I want to make the result distinct in name but don't show the name.

You could try something like this.
select age, sex from (
select distinct name, age, sex from person);
I'm presuming you might have people with the same age and sex but a different name.
Otherwise just remove the name

Here is my solution (sql server 2016):
create table person (age varchar(20), [name] varchar(20), gender varchar(20))
go
insert into person values ('20', 'joe', 'm')
insert into person values ('19', 'tom', 'm')
insert into person values ('25', 'sally', 'f')
insert into person values ('28', 'Tammy', 'f')
go
select age, gender from (select distinct name, age, gender from person) t

You have to use your query as a sub query here.
From your query again select age and sex alone.
select age, sex from (select distinct name, age, sex from person) As x

Related

How to not return duplicates when comparing records in same table (A:B and B:A)

I have been stuck with this problem for a while now and can't resolve it, would greatly appreciate some guidance
I am comparing records in a persons table to see if they're possibly the same. To do this I am using a with statement to take the values I need and looking for matches
CREATE TABLE persons (
serialno VARCHAR(20) NOT NULL,
given VARCHAR(30) NOT NULL,
family VARCHAR(30) NOT NULL,
dob DATE NOT NULL,
gender VARCHAR2(20 BYTE),
address VARCHAR2(64 BYTE)
);
INSERT ALL
INTO persons ( serialno, given, family,dob,gender,address ) VALUES ( '001', 'Mick', 'Dundon','01/01/1970','Male','Main St' )
INTO persons ( serialno, given, family, dob,gender,address) VALUES ( '002', 'Mick', 'Dundon','01/01/1970', 'Male','Montague St' )
INTO persons ( serialno, given, family,dob,gender,address ) VALUES ( '003', 'Dave', 'Doyle', '13/10/1981','Male', 'Rathmines')
INTO persons ( serialno, given, family,dob,gender,address ) VALUES ( '004', 'Jim', 'Morrison', '15/08/1956','Male','Newtown')
INTO persons ( serialno, given, family, dob,gender,address) VALUES ( '005', 'Sam', 'Wise', '12/12/1992','Male','High St')
SELECT 1 FROM dual;
with rec as
(select serialno,given,family,dob,gender,address
from persons)
select *
from rec r1
join rec r2
on r1.given = r2.given
and r1.family = r2.family
and r1.gender = r2.gender
and r1.serialno <> r2.serialno
the code works fine except I end up with duplicates as the R1 record will appear further down in the output as R2, and vice versa.
Is there a simple way I can avoid this kind of duplication?
You can get all the duplicates without a self-join by using the analytic COUNT function:
SELECT serialno, given, family, dob, gender, address
FROM (
SELECT serialno, given, family, dob, gender, address,
COUNT(*) OVER (PARTITION BY given, family, gender) AS num_matches
FROM persons
)
WHERE num_matches > 1;
If you also want to compare the values to the row with the same given/family/gender combination and the minimum serial number then, again you can avoid a self-join by using analytic functions:
SELECT serialno, given, family, dob, gender, address,
min_serialno, min_dob, min_address
FROM (
SELECT serialno,
given,
family,
dob,
gender,
address,
MIN(serialno) OVER (PARTITION BY given, family, gender) AS min_serialno,
MIN(dob) KEEP (DENSE_RANK FIRST ORDER BY serialno)
OVER (PARTITION BY given, family, gender) AS min_dob,
MIN(address) KEEP (DENSE_RANK FIRST ORDER BY serialno)
OVER (PARTITION BY given, family, gender) AS min_address
FROM persons
)
WHERE serialno > min_serialno;
If, in Oracle, you want to get all possible combinations then you can avoid a self-join by using a hierarchical query:
SELECT serialno, given, family, dob, gender, address,
PRIOR serialno AS p_serialno,
PRIOR dob AS p_dob,
PRIOR address AS p_address
FROM persons
WHERE LEVEL = 2
CONNECT BY
PRIOR gender = gender
AND PRIOR given = given
AND PRIOR family = family
AND PRIOR serialno < serialno
db<>fiddle here

Oracle Sql : unable to use 'With' clause when using group by 'Cube'

I have the following sample code as reference:
Create table wait_weekly as select XXX
.....;
Create table wait_weekly_prev as select
....
from
Wait_weekly
group by
cube(var1, var2);
This works fine.
However, if I put the table wait_weekly either in the 'With' clause or directly in a subquery, like
with wait_weekly as (select XXX)
Create table wait_weekly_prev as select
....
from
(select XXX...)
group by
cube(var1, var2);
`
it will give me the same error message and won't recognize a variable is an invalid identifier.. Any suggestion? thanks.
Here is the sample code, but the reality is that it works in this sample code. Just imagine it's not working, and the error message is that 'invalid identifier for one of the variables in table Test". I did remove the cube( lastname, sex) and replaced with nvl(Lastname,'All_lastname') as Lastname,
nvl(Sex,'All_sex') as Sex, and the codes work; but I do need cube( ..., ...).
Hope this is clear enough, thanks.
create table test (
Lastname VARCHAR2(12),
Sex VARCHAR2(12),
Age NUMBER);
insert all
into test (Lastname, Sex, Age) values ('Sun', 'M', 8)
into test (Lastname, Sex, Age) values ('Thomas','M',12)
into test (Lastname, Sex, Age) values ('Sun','F',13)
into test (Lastname, Sex, Age) values ('Thomas','F',15)
into test (Lastname, Sex, Age) values ('Berg','F',18)
SELECT 1 FROM DUAL;
Example queries:
with test_1 as
(select * from test where lastname <> 'Berg')
select
nvl(Lastname,'All_lastname') as Lastname,
nvl(Sex,'All_sex') as Sex,
sum(Age) as Age
from test_1
group by cube(Lastname, Sex);
select
nvl(Lastname,'All_lastname') as Lastname,
nvl(Sex,'All_sex') as Sex,
sum(Age) as Age
from (select * from test where lastname <> 'Berg')
group by cube(Lastname, Sex);

Return a blank string for a field SQL

Is there a way to return a blank string for a field in SQL, even if the field has data?
SELECT NAME, AGE, DOB, GENDER, CITY
FROM TABLE
I want DOB, to always return blank ''
In Oracle, an empty VARCHAR2 is equivalent to a NULL value.
So you can just do:
SELECT NAME,
AGE,
NULL AS DOB,
GENDER,
CITY
FROM TABLE
If you want to give it a specific data type then you can use CAST:
SELECT NAME,
AGE,
CAST( NULL AS DATE ) AS DOB,
GENDER,
CITY
FROM TABLE
try this:
SELECT NAME, AGE, ' ' as DOB, GENDER, CITY
FROM TABLE
You could use NVL2:
SELECT NVL2(dob, '', NULL) --rest of cols
FROM TABLE;
Please note that '' is the same as NULL. So you have:
SELECT '' AS DOB -- rest of cols
FROM TABLE;

SQL query to that limits only a subset of the records

Let's say I have a table of people, with rows name, gender (M/F), and age.
What would a SQL query look like that returns:
all female people
a maximum of 5 male people
people sorted by age
NB. This is a contrived example. Also, Postgres-specific answers welcome.
SELECT name, gender, age
FROM ( SELECT name, gender, age
FROM people
WHERE gender = 'F'
UNION ALL
( SELECT name, gender, age
FROM people
WHERE gender = 'M'
LIMIT 5
)
) x
ORDER BY age
Note the above solution doesn't pick any particular males. Apply an ordering to the male subquery if you want that.
This one orders the males by age before the pruning takes place:
SELECT name, gender, age
FROM ( SELECT name, gender, age
,ROW_NUMBER() OVER (PARTITION BY gender ORDER BY age) gender_count
FROM people
) x
WHERE gender = 'F'
OR gender_count <= 5
BTW, I've found "gender" is usually used for grammatical references. In this case "sex" would have been the terminology I would have used.

is it possible to add records to a result set after Order By in a stored procedure?

This sounds like a stupid question while I'm asking it, but I'm new to SQL and not sure if something like this is possible.
I want to select all records from a table except for 2, order them alphabetically and then append the last two to the end. Can I do this in a select statement or do I have to create a temp table and returned a result set from that?
Basically, in pseudo-code, I want to do this:
select
firstname,
lastname,
otherdata
from People
where firstname != 'john' or 'mark'
order by firstname
add John and Mark
Thanks in advance.
No, you need to use a UNION to combine queries and ORDER BY must come last. e.g.
SELECT firstname, lastname, otherdata
FROM dbo.People
WHERE firstname NOT IN ('john', 'mark')
UNION ALL
SELECT 'John', NULL, NULL
UNION ALL
SELECT 'Mark', NULL, NULL
ORDER BY firstname;
If your intention is to place those two rows last, then you need something else to order by, e.g.
SELECT firstname, lastname, otherdata, z = 1
FROM dbo.People
WHERE firstname NOT IN ('john', 'mark')
UNION ALL
SELECT 'John', NULL, NULL, z = 2
UNION ALL
SELECT 'Mark', NULL, NULL, z = 3
ORDER BY z, firstname;
You might see cute tricks where people will put the query in a subquery and apply an order by there (with the help of TOP), but beware, this is a ruse! This will not guarantee how the outer query is ordered.