Need help solving SQL Oracle Counting Characters - sql

we have a large set of data and the professor is asking us to do the following:
Amy Gray has seven characters in her name. (The space between her first and last name does not count.) J. J. Brown has ten in his name. (The space and periods in J. J. count as characters.) Allison Black-White has eighteen in hers. (The hyphen counts as a character.)
Create a view named A9T4 that will display the size and the total number of students whose combined first and last name has that size. The two column headings should be Name_Size and Students. The rows should be sorted by descending size.
Note: As a simple check of your work, the longest name in A9 has 22 characters and the three shortest names have seven characters.

I used the Oracle DUMP, SUBSTR, and REGEXP_LIKE function to get the count.
http://www.techonthenet.com/oracle/functions/dump.php
http://www.techonthenet.com/oracle/functions/substr.php
http://www.techonthenet.com/oracle/functions/regexp_substr.php
CREATE TABLE SCHEMA1.NAMES (
eval_name VARCHAR2(100 CHAR)
);
insert into SCHEMA1.NAMES values('Amy Gray');
insert into SCHEMA1.NAMES values('J. J. Brown');
insert into SCHEMA1.NAMES values('Allison Black-White');
commit;
select eval_name, REGEXP_SUBSTR(SUBSTR(DUMP(eval_name),11), '^[0-9]*')-1 from SCHEMA1.NAMES;
--returns
Amy Gray 7
J. J. Brown 10
Allison Black-White 18
DUMP('Amy Gray') -- gives us 'Typ=1 Len=8: 65,109,121,32,71,114,97,121'
SUBSTR(DUMP('Amy Gray'),11) -- starts at position eleven, giving us
'8: 65,109,121,32,71,114,97,121'
REGEXP_SUBSTR(SUBSTR(dump('Amy Gray'),11), '^[0-9]*') -- gives us '8', all digits from the beginning of the string '^' to the first non-digit, ':'
--and the -1 removes the expected space between the first and last names.

Related

SQL WHERE column values into capital letters

Let's say I have the following entries in my database:
Id
Name
12
John Doe
13
Mary anne
13
little joe
14
John doe
In my program I have a string variable that is always capitalized, for example:
myCapString = "JOHN DOE"
Is there a way to retrieve the rows in the table by using a WHERE on the name column with the values capitalized and then matching myCapString?
In this case the query would return two entries, one with id=12, and one with id=14
A solution is NOT to change the actual values in the table.
A general solution in Postgres would be to capitalize the Name column and then do a comparison against an all-caps string literal, e.g.
SELECT *
FROM yourTable
WHERE UPPER(Name) = 'JOHN DOE';
If you need to implement this is Knex, you will need to figure out how to uppercase a column. This might require using a raw query.

Name Correction

Name Correction
As the wedding season is on, John has been given the work of printing guest names on wedding cards. John has written code to print only those names that start with upper-case alphabets and reject those that start with lower-case alphabets or special characters.
Your job is to do the following:
1.Correct the rejected names (names which start with lower case or with a special character). You have to change the first alphabet of the rejected name to Upper case and in the case of special character there will be no change.
2.Output the newly corrected names in ascending order.
Table format
Table: person
Field Type
name varchar(20)
Sample
Sample person table
name
mohit
Kunal
manoj
Raj
tanya
#man
Sample output table
name
#man
Manoj
Mohit
Tanya
Solution Attempted: IN SQL SERVER 2014
select name
from person as per
where (left(per.name,1) like '%[^A-Z]%' or left(per.name,1) like '% %')
union
select Upper(left(per.name,1))+right(per.name,len(per.name)-1)
from person as per
where left(per.name,1)<>left(Upper(per.name),1)
collate Latin1_General_CS_AI
order by per.name
Sample Test Cases Passes,
Still getting wrong answer in some competitor exam.
Please suggest what test case i have not handled.
Since you are only interested in correcting lower case and reporting special characters in the first character position I would use ascii comparision rather than regex.
select name, ascii(left(name,1)),
case
when ascii(left(name,1)) between 97 and 122 then
concat(char(ascii(left(name,1)) - 32),substring(name,2,len(name) -1))
else name
end name
from t
where ascii(left(name,1)) <= 64 or
ascii(left(name,1)) >= 91

SQL get student with last name 5 characters

I have a table called Students.
This table has two fields (ID, Name)
i need to Select all the students whose last name have 5 characters.
For example if i have in this table two records.
Student 1: ID - 1
Name - Roman Jatt Pearce
Student 2: ID:2
Name: Matt Crazy
The query i wanted should only return Matt Crazy since his last name has 5 characters and roman pearce's doesnt.
someone told me to use charindex but i dont really know how to implement it
any suggestion?
Assuming the format of Name is always "First Middle Last", no names contain spaces, and there are no other things like generation listed (Jr., Sr., et al).
SELECT *
FROM Students
WHERE CHARINDEX(' ', REVERSE(Name)) = 6
How about
select * from Students where Name like '% _____'
with dash symbol coming five times

sql combine two columns that might have null values

This should be an easy thing to do but I seem to keep getting an extra space. Basically what I am trying to do is combine multiple columns into one column. BUT every single one of these columns might be null as well. When I combine them, I also want them to be separated by a space (' ').
What I created is the following query:
select 'All'= ISNULL(Name+' ','')+ISNULL(City+' ','')+ISNULL(CAST(Age as varchar(50))+' ','') from zPerson
and the result is:
All
John Rock Hill 23
Munchen 29
Julie London 35
Fort Mill 27
Bob 29
As you can see: there is an extra space when the name is null. I don't want that.
The initial table is :
id Name City Age InStates AllCombined
1 John Rock Hill 23 1 NULL
2 Munchen 29 0 NULL
3 Julie London 35 0 NULL
4 Fort Mill 27 1 NULL
5 Bob 29 1 NULL
Any ideas?
select 'All'= LTRIM(ISNULL(Name+' ','')+ISNULL(City+' ','')+ISNULL(CAST(Age as varchar(50))+' ','') from zPerson)
SEE LTRIM()
In the data you have posted, the Name column contains no NULLs. Instead, it contains empty strings, so ISNULL(Name+' ','') will evalate to a single space.
The simplest resolution is to change the data so that empty-strings are null. This is appropriate in your case since this is clearly your intention.
UPDATE zPerson SET Name=NULL WHERE Name=''
Repeat this for your City and Age fields if necessary.
Use TRIM() arount the ISNULL() function, or LTRIM() around the entire selected term

Sort Postcode for menu/list

I need to sort a list of UK postcodes in to order.
Is there a simple way to do it?
UK postcodes are made up of letters and numbers:
see for full info of the format:
http://en.wikipedia.org/wiki/UK_postcodes
But my problem is this a simple alpha sort doesn't work because each code starts with 1 or two letters letters and then is immediately followed by a number , up to two digits, then a space another number then a letter. e.g. LS1 1AA or ls28 1AA, there is also another case where once the numbers in the first section exceed 99 then it continues 9A etc.
Alpha sort cause the 10s to immediately follow the 1:
...
LS1 9ZZ
LS10 1AA
...
LS2
I'm looking at creating a SQL function to convert the printable Postcode into a sortable postcode e.g. 'LS1 9ZZ' would become 'LS01 9ZZ', then use this function in the order by clause.
Has anybody done this or anything similar already?
You need to think of this as a tokenization issue so SW1A 1AA should tokenize to:
SW
1
A
1AA
(although you could break the inward part down into 1 and AA if you wanted to)
and G12 8QT should tokenize to:
G
12
(empty string)
8QT
Once you have broken the postcode down into those component parts then sorting should be easy enough. There is an exception with the GIR 0AA postcode but you can just hardcode a test for that one
edit: some more thoughts on tokenization
For the sample postcode SW1A 1AA, SW is the postcode area, 1A is the postcode district (which we'll break into two parts for sorting purposes), 1 is the postcode sector and AA is the unit postcode.
These are the valid postcode formats (source: Royal Mail PAF user guide page 8 - link at bottom of this page):
AN NAA
AAN NAA
ANN NAA
ANA NAA
AAA NAA (only for GIR 0AA code)
AANN NAA
AANA NAA
So a rough algorithm would be (assuming we want to separate the sector and unit postcode):
code = GIR 0AA? Tokenize to GI/R/ /0/AA (treating R as the district simplifies things)
code 5 letters long e.g G1 3AF? Tokenize to G/1/ /3/AF
code 6 letters long with 3rd character being a letter e.g. W1P 1HQ? Tokenize to W/1/P/1/HQ
code 6 letters long with 2nd character being a letter e.g. CR2 6XH? Tokenize to CR/2/ /6/XH
code 7 letters long with 4th character being a letter e.g. EC1A 1BB? Tokenize to EC/1/A/1/BB
otherwise e.g. TW14 2ZZ, tokenize to TW/14/ /2/ZZ
If the purpose is to display a list of postcodes for the user to choose from then I would adopt Neil Butterworth's suggestion of storing a 'sortable' version of the postcode in the database. The easiest way to create a sortable version is to pad all entries to nine characters:
two characters for the area (right-pad if shorter)
two for the district number (left-pad if shorter)
one for the district letter (pad if missing)
space
one for the sector
two for the unit
and GIR 0AA is a slight exception again. If you pad with spaces then the sort order should be correct. Examples using # to represent a space:
W1#1AA => W##1##1AA
WC1#1AA => WC#1##1AA
W10#1AA => W#10##1AA
W1W#1AA => W##1W#1AA
GIR#0AA => GI#R##0AA
WC10#1AA => WC10##1AA
WC1W#1AA => WC#1W#1AA
You need to right-pad the area if it's too short: left-padding produces the wrong sort order. All of the single letter areas - B, E, G, L, M, N, S, W - would sort before all of the two-letter areas - AB, AL, ..., ZE - if you left-padded
The district number needs to be left padded to ensure that the natural W1, W2, ..., W9, W10 order remains intact
I know this is a couple of years late but i too have just experienced this problem.
I have managed to over come it with the following code, so thought i would share as i searched the internet and could not find anything!
mysql_query("SELECT SUBSTRING_INDEX(postcode,' ',1) as p1, SUBSTRING_INDEX(postcode,' ',-1) as p2 from `table` ORDER BY LENGTH(p1), p1, p2 ASC");
This code will take a Full UK postcode and split it into 2.
It will then order by the first part of the postcode followed by the second.
I'd be tempted to store the normalised postcode in the database along with the real postcode - that way you only do the string manipulation once, and you can use an index to help you with the sort.