Assign custom labels to sql query - sql

This is a pretty simple question, I think, but I cannot find an answer for it here, or through online searching.
I am running a count query, and am having trouble with value labels and column headings
Query is
SELECT
mail_code AS "code",
COUNT(mail_code) AS "count"
FROM data.base
GROUP BY mail_code
;
I get back:
C Count
- -----
Y 110
X 785
Z 92
Questions:
How do I get the first variable (code) to display its full name, instead of a single letter?
How do I change Y, X, and Z to read "phone," "mail," and "email" ...or anything else for that matter?
The length of the mail_code variable is 1 byte...is that why only the first letter is showing up as my varname?
...I was initially warned that based on my title, it might get downvoted. OK, but I tried to look elsewhere for the answer and could not find it, IE I tried due diligence.
Thank you in advance.

Mostly, they keep a look-up table with foreign - primary key relationship. i.e. write explanation in a table with code_name and explanation columns
with values X , phone ; Y, mail : Z , email respectively,
and Join them with a SQL statement :
select d.mail_code as "code", c.explanation as "communication type", count(1) as "count"
from data_base d inner join codes c on ( d.mail_code = c.mail_code )
group by d.mail_code, c.explanation;
Where DDLs are as following to create tables :
create table codes(mail_code varchar2(1) primary key,explanation varchar2(15));
create table data_base( mail_code varchar2(1) references codes(mail_code));
Demo

Thank you all, I got about 75% of the way there.
Syntax:
COLUMN mail_code FORMAT A10
SELECT
DECODE (mail_code,
'X', 'mail',
'Y', 'phon',
'Z', 'emai') AS "code",
COUNT(*) AS "count"
FROM data.base
GROUP BY mail_code
;
Returned
code count
---- -----
mail 110
phon 785
emai 92
Double quotes are needed b/c Oracle. It'll work to change name to 'code' wo double quotes but comes up as all caps (CODE) wo them, and I can choose w double quotes.
Thank you all for your help with this!

Related

ORACLE Retrieving data from 4 tables

I have the following tables:
Students(id, name, surname)
Courses(course id)
Course_Signup(id, student_id, course_id, year)
Grades(signup_id, mark)
I want to display all the students(id, name, surname) with their final grade (where final grade = avg of the grades of all courses), but only for the students that have passed all the courses for which they have sign-up in the current year.
This is what I tried:
SELECT s."id", s."name", s."surname", AVG(g."mark") AS "finalGrade"
FROM "STUDENT" s,
"course sign-up" csn
join "GRADES" g
on csn."id" = g."signup_id"
WHERE csn."year" >= '01-01-2022'
HAVING "finalGrade" >= 5.00
GROUP BY s."id"
However, after adding the last 2 lines, regarding the finalGrade condition, I get an invalid identifier error. Why is that?
Uh, oh. Did you really create tables using lower letter case names enclosed into double quotes? If so, get rid of them (the sooner, the better) because they only cause problems.
Apart from that, uniformly use joins - in your from clause there's the student table which isn't joined to any other table and results in cross join.
Don't compare dates to strings; use date literal (as I did), or to_date function with appropriate format model.
As of error you got: you can't reference expression's alias ("finalGrade") as is in the having clause - use the whole expression.
Also, group by should contain all non-aggregated columns from the select column list.
This "fixes" error you got, but - I suggest you consider everything I said:
SELECT s."id", s."name", s."surname", AVG(g."mark") AS "finalGrade"
FROM "STUDENT" s,
"course sign-up" csn
join "GRADES" g
on csn."id" = g."signup_id"
WHERE csn."year" >= date '2022-01-01'
GROUP BY s."id", s."name", s."surname"
HAVING AVG(g."mark") >= 5.00

How to groupby in subquery SQL

I have the following query:
SELECT "IMPORTACIONCOLUMN3", "role", COUNT("IMPORTACIONCOLUMN1")
FROM MYTABLE
WHERE ID = 9
GROUP BY "IMPORTACIONCOLUMN3", "role"
This gives me the following result:
I would like to achieve the following:
The "unique" values are grouped together (i.e. Instead of having 4 values of "Robot 1" these are grouped togehter in just 1 cell summing the count values.
The second group by or subquery has to be the same count, but with role instead of "IMPORTACIONCOLUM3"
Is it possible (for the second picture) to "link" the values either by index or adding an extra column to reference them (i.e. There's two "Solicitante" with a count value of "52" but it refers to "Robot 1" and other to "Solicitante" with count value of "58" links to "Robot 2"
The second image represent visually what I'm trying to explain.
I have been trying on my own but only have reached the following:
select "IMPORTACIONCOLUMN3", count("IMPORTACIONCOLUMN1")
from
(
select "IMPORTACIONCOLUMN1", count("role"), "IMPORTACIONCOLUMN3"
from MYTABLE
WHERE ID = 9
group by "IMPORTACIONCOLUMN1", "IMPORTACIONCOLUMN3"
) as tmp
group by "IMPORTACIONCOLUMN3"
But it is not yet the result I am looking for.
Thanks in advance for your help and tips!
EDIT:
Explaining my desired output in detail
Each one of "Robot 1, 2, 3" have roles such as "Solicitante", "Gerente", etc. with different values.
i.e. The first row "Humano" value "243" is the sum of "Agente de Compras - 95", "Gerente Financiero - 37", "Gerente Solicitante - 45", "Proovedor - 31", "Solicitante - 60".
I am linking these by the column "GRAFICOCOLUMNARECURSIVOID" with contains the index of whatever "Robot" these "roles" are from.
I would like to achieve a query containing subquerys that allows me to have this output.
Try this for question number 1:
SELECT "IMPORTACIONCOLUMN3", COUNT("IMPORTACIONCOLUMN1")
FROM MYTABLE
WHERE ID = 9
GROUP BY "IMPORTACIONCOLUMN3"
the problem is Role: Robot 1 have 4 roles
and this for question 2:
SELECT "role", COUNT("IMPORTACIONCOLUMN1")
FROM MYTABLE
WHERE ID = 9
GROUP BY "role"
Question 3, I don't understand what you are asking for. Please make an example.

Completely Unique Rows and Columns in SQL

I want to randomly pick 4 rows which are distinct and do not have any entry that matches with any of the 4 chosen columns.
Here is what I coded:
SELECT DISTINCT en,dialect,fr FROM words ORDER BY RANDOM() LIMIT 4
Here is some data:
**en** **dialect** **fr**
number SFA numero
number TRI numero
hotel CAI hotel
hotel SFA hotel
I want:
**en** **dialect** **fr**
number SFA numero
hotel CAI hotel
Some retrieved rows would have something similar with each other, like having the same en or the same fr, I would like to retrieved rows that do not share anything similar with each other, how do I do that?
I think I’d do this in the front end code rather the dB, here’s a pseudo code (don’t know what your node looks like):
var seenEn = “en not in (''“;
var seenFr = “fr not in (''“;
var rows =[];
while(rows.length < 4)
{
var newrow = sqlquery(“SELECT *
FROM table WHERE “ + seenEn + “) and ”
+ seenFr + “) ORDER BY random() LIMIT 1”);
if(!newrow)
break;
rows.push(newrow);
seenEn += “,‘“+ newrow.en + “‘“;
seenFr += “,‘“+ newrow.fr + “‘“;
}
The loop runs as many times as needed to retrieve 4 rows (or maybe make it a for loop that runs 4 times) unless the query returns null. Each time the query returns the values are added to a list of values we don’t want the query to return again. That list had to start out with some values (null) that are never in the data, to prevent a syntax error when concatenation a comma-value string onto the seenXX variable. Those syntax errors can be avoided in other ways like having a Boolean of “if it’s the first value don’t put the comma” but I chose to put dummy ineffective values into the sql to make the JS simpler. Same goes for the
As noted, it looks like JS to ease your understanding but this should be treated as pseudo code outlining a general algorithm - it’s never been compiled/run/tested and may have syntax errors or not at all work as JS if pasted into your file; take the idea and work it into your solution
Please note this was posted from an iphone and it may have done something stupid with all the apostrophes and quotes (turned them into the curly kind preferred by writers rather than the straight kind used by programmers)
You can use Rank or find first row for each group to achieve your result,
Check below , I hope this code will help you
SELECT 'number' AS Col1, 'SFA' AS Col2, 'numero' AS Col3 INTO #tbl
UNION ALL
SELECT 'number','TRI','numero'
UNION ALL
SELECT 'hotel','CAI' ,'hotel'
UNION ALL
SELECT 'hotel','SFA','hotel'
UNION ALL
SELECT 'Location','LocationA' ,'Location data'
UNION ALL
SELECT 'Location','LocationB','Location data'
;
WITH summary AS (
SELECT Col1,Col2,Col3,
ROW_NUMBER() OVER(PARTITION BY p.Col1 ORDER BY p.Col2 DESC) AS rk
FROM #tbl p)
SELECT s.Col1,s.Col2,s.Col3
FROM summary s
WHERE s.rk = 1
DROP TABLE #tbl

Ways to Clean-up messy records in sql

I have the following sql data:
ID Company Name Customer Address 1 City State Zip Date
0108500 AAA Test Mish~Sara Newa Claims Chtiana CO 123 06FE0046
0108500 AAA.Test Mish~Sara Newa Claims Chtiana CO 123 06FE0046
1802600 AAA Test Company Ban, Adj.~Gorge PO Box 83 MouLaurel CA 153 09JS0025
1210600 AAA Test Company Biwel~Brce 97kehst ve Jacn CA 153 04JS0190
AAA Test, AAA.Test and AAA Test Company are considered as one company.
Since their data is messy I'm thinking either to do this:
Is there a way to search all the records in the DB wherein it will search the company name with almost the same name then re-name it to the longest name?
In this case, the AAA Test and AAA.Test will be AAA Test Company.
OR Is there a way to filter only record with company name that are almost the same then they can have option to change it?
If there's no way to do it via sql query, what are your suggestions so that we can clean-up the records? There are almost 1 million records in the database and it's hard to clean it up manually.
Thank you in advance.
You could use String matching algorithm like Jaro-Winkler. I've written an SQL version that is used daily to deduplicate People's names that have been typed in differently. It can take awhile but it does work well for the fuzzy match you're looking for.
Something like a self join? || is ANSI SQL concat, some products have a concat function instead.
select *
from tablename t1
join tablename t2 on t1.companyname like '%' || t2.companyname || '%'
Depending on datatype you may have to remove blanks from the t2.companyname, use TRIM(t2.companyname) in that case.
And, as Miguel suggests, use REPLACE to remove commas and dots etc.
Use case-insensitive collation. SOUNDEX can be used etc etc.
I think most Database Servers support Full-Text search ability, and if so there are some functions related to Full-Text search that support Proximity.
for example there is a Near function in SqlServer and here is its documentation https://msdn.microsoft.com/en-us/library/ms142568.aspx
You can do the clean-up in several stages.
Create new columns
Convert everything to upper case, remove punctuation & whitespace, then match on the first 6 to 10 characters (using self join). Assuming your table is called "vendor": add two columns, "status", "dupstr", then update as follows
/** Populate dupstr column for fuzzy match **/
update vendor v
set v.dupstr = left(upper(regex_replace(regex_replace(v.companyname,'.',''),' ','')),6)
;
Identify duplicate records
Add an index on the dupstr column, then do an update like this to identify "good" records:
/** Mark the good duplicates **/
update vendor v
set v.status = 'keep' --indicate keeper record
where
--dupes to clean up
exists ( select 1 from vendor v1 where v.dupstr = v1.dupstr
and v.id != v1.id )
and
( --keeper has longest name
length(v.companyname) =
( select max(length(v2.companyname)) from vendor v2
where v.dupstr = v2.dupstr
)
or
--keeper has latest record (assuming ID is sequential)
v.id =
( select max(v3.id) from vendor v3
where v.dupstr = v3.dupstr
)
)
group by v.dupstr
;
The above SQL can be refined to add "dupe" status to other records , or you can do a separate update.
Clean Up Stragglers
Report any remaining partial matches to be reviewed by a human (i.e. dupe records without a keeper record)
You can use SQL query with SOUDEX of DIFFRENCE
For example:
SELECT DIFFERENCE ('AAA Test','AAA Test Company')
DIFFERENCE returns 0 - 4 ( 4 = almost the same, 0 - totally diffrent)
See also: https://learn.microsoft.com/en-us/sql/t-sql/functions/difference-transact-sql?view=sql-server-2017

Invalid Column Name in SQL Server Management Studio

When I execute this query in SQL Server Management Studio, this error appears:
'Msg 207, Level 16, State 1, Line 1
Invalid column name 'ACCOUNT_NO'.'
This is the code for the query:
DECLARE #largeaccnumber INT = ACCOUNT_NO
DECLARE #smallaccnumber INT
SET #smallaccnumber = (SELECT LEFT(#largeaccnumber, 6))
SELECT DNADRX.CODE,
DNADDR.NAME,
DNADDR.TYPE,
DNADDR.MAIL_NAME,
ADDRESS_LINE1,
ADDRESS_LINE2,
ADDRESS_LINE3,
TOWN_CITY,
COUNTY_STATE,
COUNTY_STATE_CODE,
COUNTRY,
POST_ZIP,
LAST_STAT_DATE,
ACCOUNT_NO
FROM DNADRX,
DNADDR,
BACCNT
WHERE DNADDR.CODE = DNADRX.ADDRESS_CODE
AND DNADDR.CODE = #smallaccnumber
ORDER BY DNADRX.CODE
I want the query to display the data from the columns of the different tables (the columns are listed in the SELECT bit of the query) from 3 different tables (DNADRX, DNADDR, BACCNT), and the factor linking all 3 tables together is the 6 digit code (ACCOUNT_NO in the BACCNT table, ADDRESS_CODE in the DNADRX table and CODE in the DNADDR table). Originally, ACCOUNT_NO from table BACCNT was 8 digits long, but I reduced it to the first 6 digits using SELECT LEFT and assigned this 6 digit value to the variable #smallaccnumber.
Whenever I try to execute the query, it keeps telling me that 'ACCOUNT_NO' is an invalid code name. I have checked the spelling, refreshed using IntelliSense and tried 'BACCNT.ACCOUNT_NO' instead of just 'ACCOUNT_NO' on the first line of the query but it still won't work (instead it says that the multi-part identifier could not be bound when I try 'BACCNT.ACCOUNT_NO').
I am really new to SQL coding so sorry if the answer to my problem is really simple.
Thank you for your assistance :)
You can try something like this.
This assumes you know the 6 character code. This query will only find results IF there is a record matching in EVERY table. If one table doesn't find a matching record this query will return NOTHING. If you want to find a row even if a recrod is missing from a table, replace the "INNER JOIN" with "LEFT OUTER JOIN"
SELECT Dnadrx.Code,
Dnaddr.Name,
Dnaddr.Type,
Dnaddr.Mail_Name,
Address_Line1,
Address_Line2,
Address_Line3,
Town_City,
County_State,
County_State_Code,
Country,
Post_Zip,
Last_Stat_Date,
Account_No
FROM Dnaddr
INNER JOIN BACCNT ON DNAADDR.CODE = BACCNT.ACCOUNT_NO
INNER JOIN Dnadrx ON Dnaaddr.Code=Dnaadrx.Address_Code
WHERE Dnaddr.Code='YOUR 6 CHARACTER CODE GOES HERE'
ORDER BY Dnadrx.Code;