Using if-then or case-when-then to select from dataset - sql

I have a dataset with students in 1st, 2nd and 3rd grades. I want to select the names of all students in 1st and 2nd grades, but only students named John, Jane or Smith from 3rd grade. Here is what I have so far:
select
first_name,
grade_level
from table_with_all_students_info
-- I need an if or case when statement here saying if student is in third grade, their first name selected can only be John, Jane or Smith. My attempt is below.
case when grade_level in ('3rd grade')
then first_name in ('John', 'Jane', 'Smith')
I'm not sure what I'm getting wrong there but I'd appreciate some help. Thanks

You can UNION two queries such as this:
select first_name, grade_level
from table
where grade_level in ('1st','2nd')
union
select first_name, grade_level
from table
where grade_level = '3rd'
and first_name in ('John','Jane','Smith')

Use where with or:
select
first_name,
grade_level
from table_with_all_students_info
where (grade_level = '3rd grade' and first_name in ('John', 'Jane', 'Smith'))
or grade_level in ('1st grade', '2nd grade')
If there are only 3 grades in your data, you can replace grade_level in ('1st grade', '2nd grade') with grade_level != '3rd grade'

Related

Return the first and last name of customers whose email is not in the format of "<first_name>. <last_name>#email.org"

Hello I am new to sql and I have these question:
Return the first and last name of customers whose email is not in the format of "<first_name>.<last_name>#email.org".
and here is my code.
SELECT first_name, last_name
FROM customer
WHERE email LIKE '%<first_name>.%<last_name>%#email.org';
It returns me with 0 rows and columns where in fact all emails are in the correct format.
It seems I am wrong in my 'LIKE' statement.
Schema (PostgreSQL v13)
CREATE TABLE customer (
"first_name" VARCHAR(6),
"last_name" VARCHAR(5),
"email" VARCHAR(19)
);
INSERT INTO customer
("first_name", "last_name", "email")
VALUES
('bob', 'joe', 'bob.joe#gmail.com'),
('tom', 'larry', 'tom.larry#gmail.com'),
('little', 'foot', 'lilfeet#hotmail.com');
Query
SELECT first_name, last_name
FROM customer
WHERE email LIKE first_name || '.' || last_name || '%';
first_name
last_name
bob
joe
tom
larry
View on DB Fiddle
Did you try below? Also, adding a data sample would be helpful.
SELECT first_name, last_name
FROM customer
WHERE email NOT LIKE '%'||first_name||'.%'||last_name||'%#%.%';
You can also use a regular expression:
-- Any lines where email = first_name.last_name#
SELECT first_name, last_name FROM customer WHERE email ~ format('[%s]+[.]+[%s]+#',first_name,last_name)
-- Any lines where email = *.*#
SELECT first_name, last_name FROM customer WHERE email ~ '[\w]+[.]+[\w]+#'
Result:
first_name
last_name
bob
joe
tom
larry
Demo in DBfiddle

Postgresql check for double entries

I searched for nearly one hour to solve my problem but i cant find anything.
So:
I created a table named s (Suppliers) where some Suppliers for Parts are listed, it looks like this:
insert into S(sno, sname, status, city)
values ('S1', 'Smith', 20, 'London'),
('S2', 'Jones', 10, 'Paris'),
('S3', 'Blake', 30, 'Paris'),
('S4', 'Clark', 20, 'London'),
('S5', 'Adams', 30, 'Athens');
Now i want to check this table for double entries in the column "city", so this would be London and Paris and i want to sort it by the sno and print it out.
I know that it's a bit harder in Postgres than in mySQL and i tried it like this:
SELECT sno, COUNT(city) AS NumOccurencies FROM s GROUP BY sno HAVING ( COUNT (city) > 1 );
But all i get is an empty table :(. I tried different ways but it's always the same, i don't know what to do to be honest. I hope some of you could help me out here :).
Greetings Max
You're thinking about it a little backwards. By grouping by the sno you're finding all of those rows with the same sno, not the same city. Try this instead:
SELECT
city
FROM
S
GROUP BY
city
HAVING
COUNT(*) > 1
You can then use that as a subquery to find the rows that you want:
SELECT
sno, sname, status, city
FROM
S
WHERE
city IN
(
SELECT
city
FROM
S
GROUP BY
city
HAVING
COUNT(*) > 1
)

:how to split single values of a column into two and return the values along with the length

i have a table 'test' with first name, last name in name column. How do i split first name, last name and also return the length of first name and last name.
example:
name
hello world
Thomas Edison
Christopher Columbus
I want the result as:
First_name FirstName_length last_name LastName_length
hello 5 world 5
Thomas 6 Edison 6
Christopher 11 Columbus 8
select split_part(name,' ',1) as first_name,
length(split_part(name,' ',1)) as firstname_length,
split_part(nme,' ',2) as last_name,
length(split_part(name,' ',2)) as lasttname_length from table_name
SQLFIDDLE.. for the same
Just replace your table_name and column_name with actual names
select substr("name", 1, instr("name", ' ')-1) first_name,
length(substr("name", 1, instr("name", ' ')-1)) First_Name_length ,
substr("name",instr("name", ' ')+1) Last_Name,
length(substr("name",instr("name", ' ')+1)) Last_name_length
from table_name
O/P
FIRST_NAME First_LENGTH LAST_NAME LAST_LENGTH
hello 5 world 5
Thomas 6 Edison 6
Christopher 11 Columbus 8
select First_name, length(First_name), Last_name, length(Last_name) from test
SQL Fiddle

Inserting values into tables Oracle SQL

I'm trying to insert values into an 'Employee' table in Oracle SQL. I have a question regarding inputting values determined by a foreign key:
My employees have 3 attributes that are determined by foreign keys: State, Position, & Manager. I am using an INSERT INTO statement to insert the values and manually typing in the data. Do I need to physically look up each reference to input the data or is there a command that I can use? E.g.
INSERT INTO Employee
(emp_id, emp_name, emp_address, emp_state, emp_position, emp_manager)
VALUES
(001, "John Doe", "1 River Walk, Green Street", 3, 5, 1000)
This should populate the employee table with (John Doe, 1 River Walk, Green Street, New York, Sales Executive, Barry Green). New York is state_id=3 in the State table; Sales executive is position_id=5 in the positions table; and Barry Green is manager_id=1000 in the manager table.
Is there a way in which I can input the text values of the referenced tables, so that Oracle will recognise the text and match it with the relevant ID? I hope this question makes sense will be happy to clarify anything.
Thanks!
You can expend the following function in order to pull out more parameters from the DB before the insert:
--
-- insert_employee (Function)
--
CREATE OR REPLACE FUNCTION insert_employee(p_emp_id in number, p_emp_name in varchar2, p_emp_address in varchar2, p_emp_state in varchar2, p_emp_position in varchar2, p_emp_manager in varchar2)
RETURN VARCHAR2 AS
p_state_id varchar2(30) := '';
BEGIN
select state_id
into p_state_id
from states where lower(emp_state) = state_name;
INSERT INTO Employee (emp_id, emp_name, emp_address, emp_state, emp_position, emp_manager) VALUES
(p_emp_id, p_emp_name, p_emp_address, p_state_id, p_emp_position, p_emp_manager);
return 'SUCCESS';
EXCEPTION
WHEN others THEN
RETURN 'FAIL';
END;
/
INSERT
INTO Employee
(emp_id, emp_name, emp_address, emp_state, emp_position, emp_manager)
SELECT '001', 'John Doe', '1 River Walk, Green Street', state_id, position_id, manager_id
FROM dual
JOIN state s
ON s.state_name = 'New York'
JOIN positions p
ON p.position_name = 'Sales Executive'
JOIN manager m
ON m.manager_name = 'Barry Green'
Note that but a single spelling mistake (or an extra space) will result in a non-match and nothing will be inserted.
You can insert into a table from a SELECT.
INSERT INTO
Employee (emp_id, emp_name, emp_address, emp_state, emp_position, emp_manager)
SELECT
001,
'John Doe',
'1 River Walk, Green Street',
(SELECT id FROM state WHERE name = 'New York'),
(SELECT id FROM positions WHERE name = 'Sales Executive'),
(SELECT id FROM manager WHERE name = 'Barry Green')
FROM
dual
Or, similarly...
INSERT INTO
Employee (emp_id, emp_name, emp_address, emp_state, emp_position, emp_manager)
SELECT
001,
'John Doe',
'1 River Walk, Green Street',
state.id,
positions.id,
manager.id
FROM
state
CROSS JOIN
positions
CROSS JOIN
manager
WHERE
state.name = 'New York'
AND positions.name = 'Sales Executive'
AND manager.name = 'Barry Green'
Though this one does assume that all the look-ups exist. If, for example, there is no position name 'Sales Executive', nothing would get inserted with this version.

SQL Server 2005 Full Text Search over multiple tables and columns

I'm looking for a good solution to use the containstable feature of the SQL Serve r2005 effectivly. Currently I have, e.g. an Employee and an Address table.
-Employee
Id
Name
-Address
Id
Street
City
EmployeeId
Now the user can enter search terms in only one textbox and I want this terms to be split and search with an "AND" operator. FREETEXTTABLE seems to work with "OR" automatically.
Now lets say the user entered "John Hamburg". This means he wants to find John in Hamburg.
So this is "John AND Hamburg".
So the following will contain no results since CONTAINSTABLE checks every column for "John AND Hamburg".
So my question is: What is the best way to perform a fulltext search with AND operators across multiple columns/tables?
SELECT *
FROM Employee emp
INNER JOIN
CONTAINSTABLE(Employee, *, '(JOHN AND Hamburg)', 1000) AS keyTblSp
ON sp.ServiceProviderId = keyTblSp.[KEY]
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
UNION ALL
SELECT *
FROM Employee emp
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
INNER JOIN
CONTAINSTABLE([Address], *, '(JOHN AND Hamburg)', 1000) AS keyTblAddr
ON addr.AddressId = keyTblAddr.[KEY]
...
This is more of a syntax problem. How do you divine the user's intent with just one input box?
Are they looking for "John Hamburg" the person?
Are they looking for "John Hamburg Street"?
Are they looking for "John" who lives on "Hamburg Street" in Springfield?
Are they looking for "John" who lives in the city of "Hamburg"?
Without knowing the user's intent, the best you can hope for is to OR the terms, and take the highest ranking hits.
Otherwise, you need to program in a ton of logic, depending on the number of words passed in:
2 words:
Search Employee data for term 1, Search Employee data for term 2, Search Address data for term 1, Search address data for term 2. Merge results by term, order by most hits.
3 words:
Search Employee data for term 1, Search Employee data for term 2, Search employee data for term 3, Search Address data for term 1, Search address data for term 2, Search address data for term 3. Merge results by term, order by most hits.
etc...
I guess I would redesign the GUI to separate the input into Name and Address, at a minimum. If that is not possible, enforce a syntax rule to the effect "First words will be considered a name until a comma appears, any words after that will be considered addresses"
EDIT:
Your best bet is still OR the terms, and take the highest ranking hits. Here's an example of that, and an example why this is not ideal without some pre-processing of the input to divine the user's intent:
insert into Employee (id, [name]) values (1, 'John Hamburg')
insert into Employee (id, [name]) values (2, 'John Smith')
insert into Employee (id, [name]) values (3, 'Bob Hamburg')
insert into Employee (id, [name]) values (4, 'Bob Smith')
insert into Employee (id, [name]) values (5, 'John Doe')
insert into Address (id, street, city, employeeid) values (1, 'Main St.', 'Springville', 1)
insert into Address (id, street, city, employeeid) values (2, 'Hamburg St.', 'Springville', 2)
insert into Address (id, street, city, employeeid) values (3, 'St. John Ave.', 'Springville', 3)
insert into Address (id, street, city, employeeid) values (4, '5th Ave.', 'Hamburg', 4)
insert into Address (id, street, city, employeeid) values (5, 'Oak Lane', 'Hamburg', 5)
Now since we don't know what keywords will apply to what table, we have to assume they could apply to either table, so we have to OR the terms against each table, UNION the results, Aggregate them, and compute the highest rank.
SELECT Id, [Name], Street, City, SUM([Rank])
FROM
(
SELECT emp.Id, [Name], Street, City, [Rank]
FROM Employee emp
JOIN [Address] addr ON emp.Id = addr.EmployeeId
JOIN CONTAINSTABLE(Employee, *, 'JOHN OR Hamburg') AS keyTblEmp ON emp.Id = keyTblEmp.[KEY]
UNION ALL
SELECT emp.Id, [Name], Street, City, [Rank]
FROM Employee emp
JOIN [Address] addr ON emp.Id = addr.EmployeeId
JOIN CONTAINSTABLE([Address], *, 'JOHN OR Hamburg') AS keyTblAdd ON addr.Id = keyTblAdd.[KEY]
) as tmp
GROUP BY Id, [Name], Street, City
ORDER BY SUM([Rank]) DESC
This is less than ideal, here's what you get for the example (in your case, you would have wanted John Doe from Hamburg to show up first):
Id Name Street City Rank
2 John Smith Hamburg St. Springville 112
3 Bob Hamburg St. John Ave. Springville 112
5 John Doe Oak Lane Hamburg 96
1 John Hamburg Main St. Springville 48
4 Bob Smith 5th Ave. Hamburg 48
But that is the best you can do without parsing the input before submitting it to SQL to make a "best guess" at what the user wants.
I had the same problem. Here is my solution, which worked for my case:
I created a view that returns the columns that I want. I added another extra column which aggregates all the columns I want to search among. So, in this case the view would be like
SELECT emp.*, addr.*, ISNULL(emp.Name,'') + ' ' + ISNULL(addr.City, '') AS SearchResult
FROM Employee emp
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
After this I created a full-text index on SearchResult column. Then, I search on this column
SELECT *
FROM vEmpAddr ea
INNER JOIN CONTAINSTABLE(vEmpAddr, *, 'John AND Hamburg') a ON ea.ID = a.[Key]