How to search for matching staff number in sql - sql

I am new to sql and trying to come up with a sql query which will list me the duplicate staff which were created in our system.
We have one staff which is created with id as 1234 and the same user has another account starting with staff id 01234. Is there anyway i can get the matching staff
Once i come up with correct duplicates i will than want to delete the accounts which don't have "0" at the start e.g deleted 1234 and only keep 01234
below is the sql
SELECT tps_user.tps_title AS [Name] , tps_user_type.tps_title AS [User Type]
FROM tps_user INNER JOIN
tps_user_type ON tps_user.tps_user_type_guid = tps_user_type.tps_guid
WHERE (tps_user.tps_title IN
(SELECT tps_title AS users
FROM tps_user AS t1
WHERE (tps_deleted = 0)
GROUP BY tps_title
HAVING (COUNT(tps_title) > 1))) AND (tps_user.tps_deleted = 0)

When you do you select try this:
SELECT DISTINCT CONVERT(INT,ID)
FROM your_table
WHERE ...
OR
SELECT ID
FROM your_table
WHERE ...
GROUP BY ID
This will convert all the id's to an int temporarily so when the distinct evaluates duplicates everything will be uniform to give you an accurate representation of the duplicates.
IF you don't want to convert them maybe convert them and insert them into a temporary table and add a flag to which ones have a leading zero. Or convert them then append a zero after you delete the duplicates since you want that anyway. It is easy to append a 0.

the below query will give you the list of duplicates with same Name and title. -
SELECT tps_user.tps_title AS [Name] ,
tps_user_type.tps_title AS [UserType],
COUNT(*) Duplicate_Count
FROM tps_user
INNER JOIN tps_user_type
ON tps_user.tps_user_type_guid = tps_user_type.tps_guid
group by tps_user.tps_title, tps_user_type.tps_title
having COUNT(*) > 1
order by Duplicate_Count desc

Select t1.stringId
from mytable t1
inner join mytable t2 on Convert(INT, t1.intId) = CONVERT(INT, t2.intId)
where t1.stringId not like '0%'
This should list all the persons that have duplicates but do not start with 0.

Related

SQL Where NOT IN returns blank

I am trying to get the rows where id are not in a list.
I have email with scores with several email for each score. I know how to get the max score for each email then I want to delete other rows. I try to delete all rows that are not in the list of max score but it does not work.
SELECT *
FROM mkgaction AS a
WHERE id NOT IN (SELECT id
FROM
(SELECT *
FROM mkgaction AS b
ORDER BY `score` DESC) x
GROUP BY `score`)
The select id returns me the right list but the all request returns me no line...
Do you know why?
Presumably -- if your query works at all -- you are using MySQL. The syntax in that database is:
delete ma
from mkgaction ma join
(select ma2.email, max(ma2.score) as max_score
from mkgaction ma2
group by ma2.email
) ma2
on ma.email = ma2.email and ma.score < ma2.max_score;

SQL Oracle - query to return rows based on data matchng rules

I have the below data
NUMBER SEQUENCE_NUMBER
CA00000045 AAD508
CA00000045 AAD508
CA00000046 AAD509
CA00000047 AAD510
CA00000047 AAD510
CA00000047 AAD511
CA00000048 AAD511
and I would like to find out which rows do not match the following rule:
NUMBER will always be the same when the SEQUENCE_NUMBER is the same.
So in the above data 'AAD508' will mean the NUMBER value will be the same on each row where the same value appears in the SEQUENCE_NUMBER.
I want to right a query that will bring me back rows where this rule is
broken. So for example:
CA00000047 AAD511
CA00000048 AAD511
I don't know where to start with this one, so have no initial SQL i'm afraid.
Thanks
You want to self join on the data to compare each row to all others sharing the same sequence number, and then filter using a with statement to only get rows with non-matching numbers. You did not give a name for the table so I added it as "table_name" below
SELECT
a.NUMBER,
a.SEQUENCE_NUMBER
FROM table_name a
INNER JOIN table_name b
ON a.SEQUENCE_NUMBER = b.SEQUENCE_NUMBER
WHERE a.NUMBER <> b.NUMBER
GROUP BY 1,2
Threw in the group by to act as a distinct
I would simply use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.sequence_number = t.sequence_number and
t2.number <> t.number
);
If sequence_numbers() only had up to two rows, you could get each rule-breaker on one row:
select sequence_number, min(number), max(number)
from t
group by sequence_number
having min(number) <> max(number);
Or, you could generalize this to get the list of numbers on a single row:
select sequence_number, listagg(number, ',') within group (order by number) as numbers
from t
group by sequence_number
having min(number) <> max(number);

Conditional Output in SQL

I have a table (lets call it "Items") that contains a set of names, groups and statuses. For example
Name | Group | Status
FF A ON
GG A OFF
HH A UNKN
ZZ B ON
YY B OFF
I am trying to aggregate the status of all records in a given group, by taking the most relevant status (in order by relevance: UNKN, OFF, ON).
Edit 1: These statuses are only examples, and their names and orders could change in my application, so that should be configurable in the query.
For example, if I query for the overall status of Group A, the status should be UNKN, and if I query for Group B, the status should be OFF.
Edit 2: It is possible that there are multiples of the same status for a group. For example two records that are UNKN.
The query I have managed is to select all items from a group. For example Group A:
SELECT Items.[Group], Items.[Status]
FROM Items
WHERE (((Items.[Group])="A"));
Produces:
Name | Group | Status
FF A ON
GG A OFF
HH A UNKN
but I can't boil it down to the single most relevant status for every group. I have tried to use CASE WHEN and IF EXISTS but I can't get it to work. Any input?
Edit 3:
As an example of the desired output for the overall group status:
Group | OverallStatus
A UNKN
B OFF
If you can build another table, a simple solution would be:
Add another table with the values in the order you want.
Then, just build a query like this:
SELECT TOP 1 Table1.*, Table2.VALUE
FROM Table1 INNER JOIN Table2 ON Table1.status = Table2.STATUS
WHERE Table1.group="A"
ORDER BY Tabla2.VALUE DESC
If the status changes or are added new ones, or you need a new order, just refresh the new table.
EDIT
Acording to the new info by OP, the query can be write in another way. The previous query take into account showing all the record in table1.
If you only need the group and the "max" status, you can use something like this:
SELECT A.group, Table2.STATUS
FROM (SELECT Table1.group, Max(Table2.VALUE) AS MaxVALUE
FROM Table1 INNER JOIN Table2 ON Tabla1.status = Table2.STATUS
GROUP BY Table1.group) as A INNER JOIN Table2 ON A.MaxVALUE= Table2.VALUE;
Use conditional aggregation and some other logic:
select grp,
switch(sum(iif(status = "UNK", 1 0) > 0, "UNK", -- any unknowns
sum(iif(status = "OFF", 1, 0) > 0, "OFF", -- any offs
"ON"
) as group_status
from items
group by grp;
This counts the number of each status and then uses that to determine the overall group status. Your question is not really explicit about the rules, but I think these capture what you are trying to do. It should be easy enough to modify for other rules.
Using the "length" as gauge, this should fit Access SQL:
Select *
From Items
Where Items.Name = (
Select Top 1 T.Name
From Items As T
Where T.Group = Items.Group
Order By Len(T.Status) Desc)
Assuming that the status column will have only three distinct values as shown in data example, you can try below query:
SELECT *
FROM ITEMS
WHERE (GROUP,LENGTH(STATUS)) IN (
SELECT GROUP,MAX(LENGTH(STATUS))
FROM ITEMS
GROUP BY GROUP)
Thanks,
Amitabh

My query is returning duplicates

I have written an SQL query to filter for a number of conditions, and have used distinct to find only unique records.
Specifically, I need only for the AccountID field to be unique, there are multiple AddressClientIDs for each AccountID.
The query works but is however producing some duplicates.
Further caveats are:
There are multiple trans for each AccountID
There can be trans record both Y and N for an AccountID
I only want to return AccountIDs which have transaction for statuses other than what's specified, hence why I used not in, as I do not want the 2 statuses.
I would like to find only unique values for the AccountID column.
If anyone could help refine the query below, it would be much appreciated.
SELECT AFS_Account.AddressClientID
,afs_transunit.AccountID
,SUM(afs_transunit.Units)
FROM AFS_TransUnit
,AFS_Account
WHERE afs_transunit.AccountID IN (
-- Gets accounts which only have non post statuses
SELECT DISTINCT accountid
FROM afs_trans
WHERE accountid NOT IN (
SELECT accountid
FROM afs_trans
WHERE STATUS IN (
'POSTPEND'
,'POSTWAIT'
)
)
-- This gets the unique accountIDs which only have transactions with Y status,
-- and removes any which have both Y and N.
AND AccountID IN (
SELECT DISTINCT accountid
FROM afs_trans
WHERE IsAllocated = 'Y'
AND accountid NOT IN (
SELECT DISTINCT AccountID
FROM afs_trans
WHERE IsAllocated = 'N'
)
)
)
AND AFS_TransUnit.AccountID = AFS_Account.AccountID
GROUP BY afs_transunit.AccountID
,AFS_Account.AddressClientID
HAVING SUM(afs_transunit.Units) > 100
Thanks.
Since you confirmed that you have one-to-many relationship across two tables on AccountID column, you could use Max value of your AccountID to get distinct values:
SELECT afa.AddressClientID
,MAX(aft.AccountID)
,SUM(aft.Units)
FROM AFS_TransUnit aft
INNER JOIN AFS_Account afa ON aft.AccountID = afa.AccountID
GROUP BY afa.AddressClientID
HAVING SUM(aft.Units) > 100
AND MAX(aft.AccountID) IN (
-- Gets accounts which only have non post statuses
-- This gets the unique accountIDs which only have transactions with Y status,
-- and removes any which have both Y and N.
SELECT DISTINCT accountid
FROM afs_trans a
WHERE [STATUS] NOT IN ('POSTPEND','POSTWAIT')
AND a.accountid IN (
SELECT t.accountid
FROM (
SELECT accountid
,max(isallocated) AS maxvalue
,min(isallocated) AS minvalue
FROM afs_trans
GROUP BY accountid
) t
WHERE t.maxvalue = 'Y'
AND t.minvalue = 'Y'
)
)
SELECT AFS_Account.AddressClientID
,afs_transunit.AccountID
,SUM(afs_transunit.Units)
FROM AFS_TransUnit
INNER JOIN AFS_Account ON AFS_TransUnit.AccountID = AFS_Account.AccountID
INNER JOIN afs_trans ON afs_trans.acccountid = afs_transunit.accountid
WHERE afs_trans.STATUS NOT IN ('POSTPEND','POSTWAIT')
-- AND afs_trans.isallocated = 'Y'
GROUP BY afs_transunit.AccountID
,AFS_Account.AddressClientID
HAVING SUM(afs_transunit.Units) > 100
and max(afs_trans.isallocated) = 'Y'
and min(afs_trans.isallocated) = 'Y'
Modified your query with ANSI SQL join syntax. As you are joining the tables, you just need to specify the conditions without using the sub-queries you have.

SQL query - Selecting distinct values from a table

I have a table in which i have multiple entries against a FK. I want to find out the value of FK which do not have certain entries e.g
my table has following entries.
PK----------------FK-----------------Column entries
1----------------100-----------------ab1
2----------------100-----------------ab2
3----------------100-----------------ab4
4----------------200-----------------ab1
5----------------200-----------------ab2
6----------------200-----------------ab3
7----------------300-----------------ab1
8----------------300-----------------ab2
9----------------300-----------------ab3
10---------------300-----------------ab4
Now, from this table i want to filter all those FK which do not have ab3 or ab4 in them. Certainly, i expect distinct values i.e. in this case result would be FK= 100 and 200.
The query which i am using is
select distinct(FK)
from table1
where column_entries != 'ab3'
or column_entries != 'ab4';
Certainly, this query is not fetching the desired result.
try the following :-
select distinct fk_col from table1
minus
(select distinct fk_col from table1 where col_entry='ab3'
intersect
select distinct fk_col from table1 where col_entry='ab4')
This will show all those FKs which do not have 'ab3' and 'ab4'. i.e. 100 and 200 in your case
The below script may be the solution if I got your question in a right way.
SELECT DISTINCT(TableForeignKey)
FROM Test
WHERE TableForeignKey NOT IN (
SELECT T1.TableForeignKey
FROM Test T1 INNER JOIN Test T2 ON T1.TableForeignKey = T2.TableForeignKey
WHERE T1.TableEntry = 'ab3' AND T2.TableEntry = 'ab4')
SQLFiddle Demo
You could use GROUP BY with conditional aggregation in HAVING:
SELECT FK
FROM table1
GROUP BY FK
HAVING COUNT(CASE column_entries WHEN 'ab3' THEN 1 END) = 0
OR COUNT(CASE column_entries WHEN 'ab4' THEN 1 END) = 0
;
The two conditional aggregates count 'ab3' and 'ab4' entries separately. If both end up with results greater than 0, then the corresponding FK has both 'ab3' and 'ab4' and is thus not returned. If at least one of the counts evaluates to 0, then FK is considered satisfying the requirements.