Deriving all employees from table having department id starting with 250 and 270? - oracle10g

I am using SQL plus with oracle 10.2.0.1.0. I wanted to retrieve employees who are having the department (deptid- varchar2) numbers starting with '270', '250' from the ps_job table which has more fields also.
This is the query that i have written-
select distinct deptid from ps_job
where deptid in ('250%', '270%');
It shows no rows, if i remove distinct, it gives me plenty of results with duplicate results also.

in doesn't accept wildcards. Do this:
select distinct deptid from ps_job
where (deptid like '250%'
or deptid like '270%');
Alternatively:
select distinct deptid from ps_job
where substr(deptid,1,3) in ('250', '270');
That won't use an index on deptid though, whereas the first version might (but might not).

What i did that i break down the query in 2 different queries. 1 for 250 and other for 270 and i used LIKE, previously is used IN, but somehow it didn't work correctly.
select distinct deptid from ps_job
where deptid LIKE '250%';
select distinct deptid from ps_job
where deptid LIKE '250%';
And Bob, as far as your concern goes, our DB does not have such provision as we work with effective dates and sequence, so it pretty makes sure that employee has 1 dept id currently.

Related

How to get date range between dates from the records in the same table?

I have a table with employment records. It has Employee code, status, and date when table was updated.
Like this:
Employee
Status
Date
001
termed
01/01/2020
001
rehired
02/02/2020
001
termed
03/03/2020
001
rehired
04/04/2021
Problem - I need to get period length when Employee was working for a company, and check if it was less than a year - then don't display that record.
There could be multiple hire-rehire cycles for each Employee. 10-20 is normal.
So, I'm thinking about two separate selects into two tables, and then looking for a closest date from hire in table 1, to termination in table 2. But it seems like overcomplicated idea.
Is there a better way?
Many approaches, but something like this could work:
SELECT
Employee,
SUM(DaysWorked)
FROM
(
SELECT
a1.employee,
IsNull(DateDiff(DD, a1.[Date],
(SELECT TOP 1 [Date] FROM aaa a2 WHERE a2.employee = a1.employee AND a2.[Date] > a1.[Date] and [status] <> 'termed' ORDER BY [Date] )
),DateDiff(DD, a1.[Date], getDate())) as DaysWorked
FROM
aaa a1
WHERE
[Status] = 'termed'
) Totals
GROUP BY
Totals.employee
HAVING SUM(DaysWorked) >= 365
Also using a CROSS JOIN is an option and perhaps more efficient. In this example, replace 'aaa' with the actual table name. The IsNull deals with an employee still working.

Converting counts inside query result tables to percentages of total

I have a table and want to calculate the percentage of total by store_id which each (category_id, store_id) subtotal represents. My code is below:
WITH
example_table (name, store_id)
AS
(
select name, store_id
from category
join film_category using (category_id)
join film using (film_id)
join inventory using (film_id)
join rental using (inventory_id)
)
SELECT name, store_id, cast(count(*) as numeric)/(SELECT count(*) FROM example_table)
FROM example_table
GROUP BY name, store_id
ORDER BY name, store_id
This code actually works, as in, it doesn't throw an error, only they're not the results I'm looking for. Here each of the subtotals is divided by the total across both stores and all 16 names. Instead, I want the subtotals divided by their respective store totals or divided by their respective name totals.
I'm wondering how to perform calculations on those subtotals in general.
Thanks in advance,
I believe you need to explore the possibilities of using aggregate functions combined with an OVER(PARTITION BY ...) e.g.
SELECT DISTINCT
name, store_id, store_id_count, name_count
FROM (
select name, store_id
, count(*) over(partition by store_id) as store_id_count
, count(*) over(partition by name) as name_count
from category
join film_category using (category_id)
join film using (film_id)
join inventory using (film_id)
join rental using (inventory_id)
) AS example_table
When using aggregate function with the over clause you get the wanted counts on each row of the result, and it seems that in this case you need this. Note that select distinct has been used simply to reduce the final number of rows returned, you might still need to use a group by but I am not sure if you do.
Once you have the needed values within the derived table (aliases as example_table) then it should be a simple matter of some arithmetic in the overall select clause.

How to write proper/efficient query

I have a question about the right way of writing the query.
I have an employees table, lets say there are 4 columns employee_id, department, salary, email.
There are some records without email address, I'd like to find the most efficient way to write SQL query using window function that brings the sum salary per group, divided by all of those without email address.
I have 2 solutions, of course only one is efficient, can anyone give any advice about it?
select department, sum(salary) as total
from employees
where email is null
group by 1
option 1
select a.department , a.total/(select sum(salary) from employees where email is null)
from (
select department, sum(salary) as total
from employees
where email is null
group by 1
) a
option 2
select a.department , a.total/sum(a.total) over()
from (
select department, sum(salary) as total
from employees
where email is null
group by 1
) a
I guess that query 2 is more efficient, but is it the right way? and is it valid to leave over clause empty?
Just started using PostgreSQL instead of MySQL 5.6.
Your second query is better.
The first query has to scan employees twice, while the second table only scans the (hopefully smaller) result set of the subquery to calculate the sum.
It is perfectly valid to leave the OVER clause empty, that just means that all result rows will get the same value (which is what you want).

JOINED 3 TABLES AND RETURN ONLY DISTINCT VALUES FOR MAX DATETIME

I've been trying to do this the whole 2 weeks but seems like to no avail. 3 tables involved here. but am expecting the result would be distinct case no. for the same date & user. otherwise, it must return all.
SELECT DISTINCT A.CASENO,A.DATE,A.TIME,A.TRANNO,B.PCODE,C.PDESC,A.USER
FROM tableA A
RIGHT JOIN tableB B ON A.CASENO=B.CASENO
RIGHT JOIN tableC C ON C.PCODE=B.PCODE
WHERE A.DATE between 140124 and 140331
Result still have duplicates because not same time and tranno. See result on CASENO.= 08088040
A.CASENO A.DATE A.TIME A.TRANNO B.PCODE C.PDESC A.USER
08088040 140124 182516 321 TYQ PREPLAN1 ANTHONY
08088040 140124 182131 318 TYQ PREPLAN1 ANTHONY
36360569 140128 111056 431 CVB POSTT1 MARIA
36360569 140310 113221 433 CVB POSTT1 MARIA
37386911 140213 150240 230 M2P PLANAVG FELISE
37386911 140213 135220 223 M2P PLANAVG HECTOR
39222881 140128 94122 104 TYQ PREPLAN1 ELLA
40895213 140213 164409 104 CVB POSTT1 WINNIE
51311866 140124 103203 319 M2P PLANAVG BRATT
For same date, same user and same pcode and pdesc, caseno. 08088040 came out twice because of the time and tranno difference. here the max tranno would indicate the latest transaction done on the same case no. the max time also shows that the latest datetime action done for that particular case no. was on 24/01/2014 # 18:25:16. For the same date and user, I just want the latest transaction details.
I've tried added the below script as the first condition but result was 0. It has also caused long delays before I could get the output.
WHERE A.TRANNO=(SELECT MAX(TRANNO) FROM tableA A where A.CASENO=B.CASENO)
FYI, the rests, eg. case no. 37386911 is considered unique because of different user, so I will want that to be returned. Meanwhile, case no.36360569 is also unique record because different date. although same user.
So, how should I achieve this please? Much of the examples I found was only showing for 1 table and 1 criteria to get distinct values.
The script should be those used for SQL DB2. I actually no background at all in SQL. Most of the query I've done earlier was based on trial and error but it was successful because of no complicated conditions like this.
Hopefully, somebody expert here can share the knowledge.
Thank you very much in advance.
Sincerely,
DeLL
This works for me:
SELECT A.CASENO, A.DATE, A.TIME, A.TRANNO, B.PCODE, C.PDESC, A.USER
FROM tableA A
RIGHT JOIN tableB B ON A.CASENO=B.CASENO
RIGHT JOIN tableC C ON C.PCODE=B.PCODE
WHERE A.DATE between 140124 and 140331
AND A.TRANNO = (SELECT MAX(TRANNO) FROM tableA A2 WHERE A2.CASENO=A.CASENO)
Explanation:
You can't use distinct to solve your problem, because you want data in the result that is not distinct to what you are filtering for. Your additional filter (WHERE) is the way to go.
SQLFiddle (see result): http://sqlfiddle.com/#!6/da130/2/0
Note: I had to change the column USER to USERN, since USER is a reserved word in the DB engine I selected.
Your where clause will be wrong for case no.36360569, because you only filter with caseno. The case no.36360569 has same caseno but different date, so like #JennyO'Reilly 's sample, you will leave tranno 433 but miss tranno 431.
So you should add date comparation into your subquery. But use subquery in where clause like this is inefficent. My suggestion is using CTE table to get primary key set for tableA, then inner join the others instead of your where clause.
with pkset as
(SELECT
A.CASENO,A.DATE,max(A.TRANNO) as tranno
--,A.USER I'm not sure if user is part of the primary key set, can't figure out by your question
FROM tableA
GROUP BY A.CASENO,A.DATE
)
SELECT A.CASENO, A.DATE, A.TIME, A.TRANNO, B.PCODE, C.PDESC, A.USER
FROM tableA A
INNER JOIN pkset ON pkset.CASENO=B.CASENO and pkset.DATE=A.DATE and pkset.TRANNO=a.TRANNO
RIGHT JOIN tableB B ON A.CASENO=B.CASENO
RIGHT JOIN tableC C ON C.PCODE=B.PCODE
WHERE A.DATE between 140124 and 140331
By the way, can you update RIGHT JOIN to LEFT JOIN? Right join seemed not necessary, and may let A.* B.* have null values.

T-SQL - How to write query to get records that match ALL records in a many to many join

(I don't think I have titled this question correctly - but I don't know how to describe it)
Here is what I am trying to do:
Let's say I have a Person table that has a PersonID field. And let's say that a Person can belong to many Groups. So there is a Group table with a GroupID field and a GroupMembership table that is a many-to-many join between the two tables and the GroupMembership table has a PersonID field and a GroupID field. So far, it is a simple many to many join.
Given a list of GroupIDs I would like to be able to write a query that returns all of the people that are in ALL of those groups (not any one of those groups). And the query should be able to handle any number of GroupIDs. I would like to avoid dynamic SQL.
Is there some simple way of doing this that I am missing?
Thanks,
Corey
select person_id, count(*) from groupmembership
where group_id in ([your list of group ids])
group by person_id
having count(*) = [size of your list of group ids]
Edited: thank you dotjoe!
Basically you are looking for Persons for whom there is no group he is not a member of, so
select *
from Person p
where not exists (
select 1
from Group g
where not exists (
select 1
from GroupMembership gm
where gm.PersonID = p.ID
and gm.GroupID = g.ID
)
)
You're basically not going to avoid "dynamic" SQL in the sense of dynamically generating the query at query time. There's no way to hand a list around in SQL (well, there is, table variables, but getting them into the system from C# is either impossible (2005 & below) or else annoying (2008)).
One way that you could do it with multiple queries is to insert your list into a work table (probably a process-keyed table) and join against that table. The only other option would be to use a dynamic query such as the ones specified by Jonathan and hongliang.