db2 between query for char columns - sql

I have a scenario where there is a table like below
Table Name:Employee
id EmpName(char 4) -always 4 chars only
1 ARUN
2 BALA
3 LOKI
I wanted a Db2 query which should get me the range of employees who's name starting with A to D. Meaning employees whose name starts with A,B,C and D should be displayed
I have tried this query
select * from employee where empname between 'A000' and 'DZZZ'
Its not working properly

Switch to 'AAAA' as start value.
where empname between 'AAAA' and 'DZZZ'
Will perform much better, if empname is indexed.
ANSI SQL compliant and portable, should work fine on both DB2 and Postgresql.
EDIT:
If empnames shorter than 4 characters will be stored, you can change to:
where empname between 'A' and 'DZZZ'
(Will not miss employee 'A'.)

Use the following version:
select e.*
from employee e
where e.empname >= 'A' and
e.empname < 'E'
This does exactly what you are asking for -- and making no assumptions about the second character. In addition, it is index-safe, if you have an index on empname (although you are selecting so many rows that indexes probably are not relevant).

Try this
select empname from employee where empname like 'A%' or
empname like 'B%' or empname like 'C%' or
empname like 'D%'
order by empname

Try this too
select empname from employee where empname
REGEXP'^[ABCD]'

Related

"NOT IN" SQL across 2 oracle databases

I have 2 Oracle databases A & B. I connect to A and run following SQLs:
SELECT * FROM employee has 2000 rows.
SELECT empId FROM B.xx has 700 rows.
SELECT * FROM employee ​WHERE empId IN (SELECT empId FROM B.xx) has 698 rows.
SELECT * FROM employee WHERE empId NOT IN (SELECT empId FROM B.xx) return nothing!!!
I don't know why the last SQL didn't return anything. Is it because of "cross database"?
I can't re-produce this if I replace B.xx to another table in A.
The most probable reason is that empId has NULL values in the table B.xx.
Try to run
SELECT * FROM employee WHERE empId NOT IN (SELECT empId FROM B.xx where empId is not NULL)
this will give you a valid count.
That's just how not in works.
NOT IN does not behave as expected if any of the results returned by the subquery are NULL. As you observe, it returns no rows at all.
For this reason, I strongly recommend always using NOT EXISTS:
SELECT e.*
FROM employee e
WHERE NOT EXISTS (SELECT 1 FROM B.xx x WHERE x.empId = e.empId);
Although you can fix the problem by adding a WHERE x.empId IS NOT NULL, I think that is a dangerous habit. Sometime you are likely to leave out the WHERE clause and mistakenly think that there are no mismatches (yes, this has happened to me). This cannot happen if you always use NOT EXISTS.

Optional condition in Oracle 10g

For a dummy test, I want to show a list of employees in a web form.
There is a drop down on the web form that contains a short list of departments, like this:
All Depts
Sales Dept
Marketing Dept
Communication Dept
HR Dept
Finance Dept
IT Dept
The drop down item of All Depts has a value of 0.
The following fiddle shows you what I am trying to do:
http://sqlfiddle.com/#!4/59d1f/2
I know I can do this:
IF (deptid = 0) THEN
select firstname, lastname from employees;
ELSE
select firstname, lastname from employees where deptid = :p_deptid
END IF;
But my real situation has a much more convoluted select query that involves joins of multiple tables. So, I don't wanna clutter up my script with repetitive codes.
Can I achieve my goal using CASE WHEN? Or do I have to use dynamic SQL?
Thanks.
SELECT firstname, lastname
FROM employees
WHERE 0 = :p_deptid
OR dept_id = :p_deptid

How to extract tuples from a table using the projection criteria as month name in oracle?

I have a table 'emp' whose schema is defined as(empno, ename,hiredate) ,I am trying to project out the names of all those employees who joined in the moth of January , so for this I wrote the below query but it not printing any records ,It works fine if I don't use the where clause , else it is not working .
select ename from emp where ( to_char(to_date(extract(month from hiredate),'MM'),'MONTH')) like 'JANUARY'​
Please guide me where I am making mistake .
It is unnecessarily too complicated.
Try to run this select:
select hiredate,extract(month from hiredate) from emp
Then if January is 1 from this select and there arent any mistakes, you can use:
select ename from emp where extract(month from hiredate)=1
Try this:
select ename from emp where ( to_char(to_date(extract(month from hiredate),'MONTH'),'MONTH')) like 'JANUARY'​

Need to arrange employee names as per their city column wise

I have written a query which extracts the data from different columns group by city name.
My query is as follows:
select q.first_name
from (select employee_id as eid,first_name,city
from employees
group by city,first_name,employee_id
order by first_name)q
, employees e
where e.employee_id = q.eid;
The output of the query is employee names in a single column grouped by their cities.
Now I would like to enhance the above query to classify the employees by their city names in different columns.
I tried using pivot to make this work. Here is my pivot query:
select * from (
select q.first_name
from (select employee_id as eid,first_name,city
from employees
group by city,first_name,employee_id
order by first_name)q
, employees e
where e.employee_id = q.eid
) pivot
(for city in (select city from employees))
I get some syntax issue saying missing expression and I am not sure how to use pivot to achieve the below expected output.
Expected Output:
DFW CH NY
---- --- ---
TripeH John Hitman
Batista Cena Yokozuna
Rock James Mysterio
Appreciate if anyone can guide me in the right direction.
Unfortunately what you are trying to do is not possible, at least not in "straight" SQL - you would need dynamic SQL, or a two-step process (in the first step generating a string that is a new SQL statement). Complicated.
The problem is that you are not including a fixed list of city names (as string literals). You are trying to create columns based on whatever you get from (select city from employees). Thus the number of columns and the name of the columns is not known until the Oracle engine reads the data from the table, but before the engine starts it must already know what all the columns will be. Contradiction.
Note also that if this was possible, you almost surely would want (select distinct city from employees).
ADDED: The OP asks a follow-up question in a comment (see below).
The ideal arrangement is for the cities to be in their own, smaller table, and the "city" in the employees table to have a foreign key constraint so that the "city" thing is manageable. You don't want one HR clerk to enter New York, another to enter New York City and a third to enter NYC for the same city. One way or the other, first try your code by replacing the subquery that follows the operator IN in the pivot clause with simply the comma-separated list of string literals for the cities: ... IN ('DFW', 'CH', 'NY'). Note that the order in which you put them in this list will be the order of the columns in the output. I didn't check the entire query to see if there are any other issues; try this and let us know what happens.
Good luck!
select
(CASE WHEN CITY="DFW" THEN EMPLOYEE_NAME END) DFW,
(CASE WHEN CITY="CH" THEN EMPLOYEE_NAME END) CH,
(CASE WHEN CITY="NY" THEN EMPLOYEE_NAME END) NY
FROM employees
order by first_name
Maybe you need to transpose your result. See this link . I think DECODE or CASE works best for your case:
select
(CASE WHEN CITY="DFW" THEN EMPLOYEE_NAME END) DFW,
(CASE WHEN CITY="CH" THEN EMPLOYEE_NAME END) CH,
(CASE WHEN CITY="NY" THEN EMPLOYEE_NAME END) NY
FROM employees
order by first_name
Normally I would "edit" my first answer, but the question has changed so much, it's quite different from the original one so my older answer can't be "edited" - this now needs a completely new answer.
You can do what you want with pivoting, as I show below. Wondering why you want to do this in basic SQL and not by using reporting tools, which are written specifically for reporting needs. There's no way you need to keep your data in the pivoted format in the database.
You will see 'York' twice in the Chicago column; you will recognize that's on purpose (you will see I had a duplicate row in the "test" table at the top of my code); this is to demonstrate a possible defect of your arrangement.
Before you ask if you could get the list but without the row numbers - first, if you are simply generating a set of rows, those are not ordered. If you want things ordered for reporting purposes, you can do what I did, and then select "'DFW'", "'CHI'", "'NY'" from the query I wrote. Relational theory and the SQL standard do not guarantee the row order will be preserved, but Oracle apparently does preserve it, at least in current versions; you can use that solution at your own risk.
max(name) in the pivot clause may look odd to the uninitiated; one of the weird limitations of the PIVOT operator in Oracle is that it requires an aggregate function to be used, even if it's over a set of exactly one element.
Here's the code:
with t (city, name) as -- setting up input data for testing
(
select 'DFW', 'Smith' from dual union all
select 'CHI', 'York' from dual union all
select 'DFW', 'Matsumoto' from dual union all
select 'NY', 'Abu Osman' from dual union all
select 'DFW', 'Adams' from dual union all
select 'CHI', 'Wilson' from dual union all
select 'CHI', 'Arenas' from dual union all
select 'NY', 'Theodore' from dual union all
select 'CHI', 'McGhee' from dual union all
select 'NY', 'Zhou' from dual union all
select 'NY' , 'Simpson' from dual union all
select 'CHI', 'Narayanan' from dual union all
select 'CHI', 'York' from dual union all
select 'NY', 'Perez' from dual
)
select * from
(
select row_number() over (partition by city order by name) rn,
city, name
from t
)
pivot (max(name) for city in ('DFW', 'CHI', 'NY') )
order by rn
/
And the output:
RN 'DFW' 'CHI' 'NY'
---------- --------- --------- ---------
1 Adams Arenas Abu Osman
2 Matsumoto McGhee Perez
3 Smith Narayanan Simpson
4 Wilson Theodore
5 York Zhou
6 York
6 rows selected.

Treating Null values and duplicate records in SQL Server

I have a scenario where I am working on SQL Server Reporting Services for creating a tablular report and stuck at a point where I get duplicate values for one column. Below is the sample output from the code:
AppID EmpID EmpName
2002912 81555 NULL
2002912 81588 Jenn - 81588
2026880 9328 NULL
2026880 9628 Brad - 09628
2027065 92174 Julie - 92174
2027065 92714 NULL
2028989 72138 NULL
2028989 91366 Alan - 91366
2029233 17438 NULL
2029233 53712 Brad - 53712
2031585 37902 NULL
2031588 17723 Richard - 17723
2031591 54551 Paula - 54551
2031593 52240 Sarah - 52240
2031597 72778 Daisy - 72778
2031603 12659 NULL
Notice the first coulmn (AppID) has few duplicates and the corresponding column EmpName is either Null or has some value. I want to eliminate all the duplicate AppID's where the EmpName is null.
This could have been straight forward if there were no null values for unique AppID's (Refer to the last row) also I can't hardcode as I am dealing with large number of data.
Also please note, all these three columns are coming from different table and have been LEFT JOIN to AppID table. Please let me know if you require to see the code, I didn't paste it here as it is little complex and though might not be required.
Any kind of help and suggestion is appreciated.Thank you
Use the ROW_NUMBER function in a CTE and then pick the first row. Though if there is more than one EmpName which is NOT NULL you will only get the first one in alphabetical order.
WITH AppAndEmp AS
(
SELECT
AppID
, EmpID
, EmpName
, ROW_NUMBER() OVER(PARTITION BY AppId
ORDER BY (CASE WHEN EmpName IS NULL THEN 0 ELSE 1 END) DESC
, EmpName) AS EmpOrder
FROM
dbo.App
LEFT JOIN dbo.Emp
ON App.AppId = Emp.AppId
)
SELECT
*
FROM
AppAndEmp
WHERE
EmpOrder = 1
EDIT
#djphatic: Thanks to your comment. I corrected my answer.
-- These are those who have set a EmpName but have an invalid row too
select * from data where AppID in (
select AppID from data group by AppID having count(AppID) > 1
)
and empname is not null
union
-- These are those who MIGHT have set a EmpName or NULL
select * from data where AppID in (
select AppID from data group by AppID having count(AppID) = 1
)
=> SQLFiddle
For the sake of the failure I leave my previous incorrect answer down here:
You might try this one:
select AppID, min(empid) EmpID, min(EmpName) EmpName
from data
group by AppID
SQLFiddle:
http://sqlfiddle.com/#!3/67cf0/1/0
MIN ignores any null values.
Docs for MIN in SQL Server: http://msdn.microsoft.com/en-us/library/ms179916.aspx