SQL first occurrence of a string - sql

I have a query which returns results like
Jim 456
Joe 567
Joe 789
Jane 456
What I want to do is have 456 only appear once and take the first name (Jim).
Query looks like
select
p.id_id as num_id, p.FIRST_NAME || ' ' || p.LAST_NAME as Name_
from DWH.V_TABLE p
where p.id_id > 100
The reasons for this is I need each to have only one owner, not two

select p.id_id as num_id,
p.FIRST_NAME || ' ' || p.LAST_NAME as Name_
from DWH.V_TABLE p
where p.id_id>100
LIMIT 1
Does that what you need? It will return only the first result. Also see SQL Limit

Based on the comments above The ask is now I just need one person to take ownership of each result so that they can work on an assigned task. It doesn't matter which of the id's owners it is
the following Query will meet that need.
select p.id_id as num_id
,MIN(p.FIRST_NAME || ' ' || p.LAST_NAME) as Name_
from DWH.V_TABLE p
where p.id_id > 100
GROUP BY
p.id_id

Assuming the "456" is the value stored in the id_id column, then this should do it:
select num_id,
name_
from (
select p.id_id as num_id,
p.first_name || ' ' || p.last_name as name_
row_number() over (partition by p.id_id order by p.FIRST_NAME || ' ' || p.LAST_NAME) as rn
from dwh.v_table p
where p.id_id > 100
) t
where rn = 1;

Based on the comments and the question
Presuming you have a date field to check the real owner, or you can filter the records based on their occurrence in anothertable, I'd say that if you just want to get rid of the duplicates for the ID, use the "distinct" keyword.
select distinct p.id_id as num_id, p.FIRST_NAME || ' ' || p.LAST_NAME as Name_
from DWH.V_TABLE p
where p.id_id > 100
You can also make a self join table (table join to self using p.id_id) and filter the results where "First".name<"Second".name, "First" and "Second" being the aliases of the same table output. (This is only for the case, if you have any sorting criteria base on alphabetical precedence)

Related

How to sort when you are using UNION operator in Oracle SQL. I am using two select statements and UNION operator, I want to sort results of both query

I am trying to solve HackerRank SQL - The PADS question.
The Question is:
Generate the following two result sets:
Query an alphabetically ordered list of all names in OCCUPATIONS, immediately followed by the first letter of each profession as a parenthetical (i.e.: enclosed in parentheses). For example: AnActorName(A), ADoctorName(D), AProfessorName(P), and ASingerName(S).
Query the number of ocurrences of each occupation in OCCUPATIONS. Sort the occurrences in ascending order, and output them in the following format:
There are a total of [occupation_count] [occupation]s.
where [occupation_count] is the number of occurrences of an occupation in OCCUPATIONS and [occupation] is the lowercase occupation name. If more than one Occupation has the same [occupation_count], they should be ordered alphabetically.
My Solution is:
SELECT NAME || '(' || SUBSTR(OCCUPATION,1,1) || ')'
FROM OCCUPATIONS
ORDER BY NAME
UNION
SELECT 'There are a total of ' || COUNT(OCCUPATION) || ' ' || LOWER(OCCUPATION) || 's.'
FROM OCCUPATIONS
GROUP BY OCCUPATION
ORDER BY OCCUPATION;
OP:
ERROR at line 4:
ORA-00933: SQL command not properly ended
(It seems, we cannot use ORDER BY BEFORE UNION)
I revised my code to:
SELECT NAME || '(' || SUBSTR(OCCUPATION,1,1) || ')'
FROM OCCUPATIONS
UNION
SELECT 'There are a total of ' || COUNT(OCCUPATION) || ' ' || LOWER(OCCUPATION) || 's.'
FROM OCCUPATIONS
GROUP BY OCCUPATION
ORDER BY NAME, OCCUPATION;
OP:
ERROR at line 7:
ORA-00904: "NAME": invalid identifier
Please, help me out here.
Generate the following two result sets
You are NOT generating two result sets. You are performing two SELECTs and trying to merge them into a single result set using UNION and that is not what the question asks for. Stop using UNION and use two queries.
The first result set would be:
SELECT NAME || '(' || SUBSTR(OCCUPATION,1,1) || ')'
FROM OCCUPATIONS
ORDER BY NAME;
The second result set would be:
SELECT 'There are a total of ' || COUNT(OCCUPATION) || ' ' || LOWER(OCCUPATION) || 's.'
FROM OCCUPATIONS
GROUP BY OCCUPATION
and then you need to ORDER BY the number of occurrences AND then by the occupation name (which I leave to you to solve).
Since you're wanting to output two ordered sets of data in one query, the easiest way is to assign an identifier to each query and then order by that and the column you want to order by, e.g.:
SELECT info
FROM (SELECT 1 qry, NAME || '(' || SUBSTR(OCCUPATION,1,1) || ')' info
FROM OCCUPATIONS
UNION ALL
SELECT 2 qry, 'There are a total of ' || COUNT(OCCUPATION) || ' ' || LOWER(OCCUPATION) || 's.' info
FROM OCCUPATIONS
GROUP BY OCCUPATION)
ORDER BY qry, info;
Note that, because the two queries aren't going to return the same rows, I've used a UNION ALL, since a UNION does a DISTINCT on the resultant data set, whereas UNION ALL doesn't. Also, I'm assuming that if you had two different people with the same name and occupation (e.g. different birth dates), you should output both rows, rather than one row?
Note also that when you have a UNION/UNION ALL query, the output columns inherit the column name from the first query, which is why your second query was giving you the invalid identifier error (you hadn't given your column an alias!).
Please try here hope this help:
select name||'('||SUBSTR(OCCUPATION,1,1)||')' as col
from OCCUPATIONS
UNION ALL
select
'There are a total of '||count(occupation)||' '||LOWER(occupation)||'s.' as col
from OCCUPATIONS
group by occupation
order by col
;
If we need to tune up performance and we also know the 2 selection is not duplicate, just use UNION ALL .

Generate a list of rentals, with the client's information for the outlet with the most rentals

I have 4 tables : RentalAgreement (Rentals), Clients, vehicle and outlet.
I need to list rentalAgreementNumbers of THE outlet with the highest rentals with client info and outlet address.
Thanks!
So far, I am getting all 11 rows - that is, all agreements for all outlets
SELECT outlet.Street || ' ' || outlet.City || ', ' || outlet.state || ' - ' || outlet.zipcode AS "Outlet Street Address", rentalNo AS "ID", startDate AS "Start Date", returnDate AS "Return Date", clientName, client.Phone
FROM
client JOIN (ragreement JOIN (vehicle JOIN outlet USING (outNo)) USING (licenseNo)) USING (clientNo)
GROUP BY outlet.Street || ' ' || outlet.City || ', ' || outlet.state || ' - ' || outlet.zipcode, rentalNo, startDate, returnDate, clientName, client.Phone
HAVING COUNT(rentalNo) = (SELECT
MAX(COUNT(rentalNo))
FROM
ragreement
GROUP BY (rentalNo));
How can I modify this to get only 5 rental agreements listed for outlet1 - which has the highest rental agreements in my table?
After the select command, you can set a limit. Mssql syntaxt for this is
Select top(5) [columns] from....
You also need to add a order by clause at the end of the query
... Order by [columns or calculations]

SQL query group by and select the maximum absolute value

"Table1" structure is as shown below:
source table table1
Player_NAME || Player_NUMBER || Client_name || Client_country || Player_country|| Rating
GERALD || A1234 || BENFIELD || IND || IND || 76
GERALD ||A6578 || ROTFIELD || USA || USA || 64
KUMAR || P1234 || LFV || ARG || ARG || -24
KUMAR || P5678 ||JEURASIN || ARG || TUR ||-32
KUMAR || P0101 ||ARGENIA ||ARG ||POL ||-16
ANDREW ||R1234 || GENMAD || GER || GER || 23
I need to select the records from above table “Table1” and copy them to “Table2”.
I need to select the player record from table1 which satisfy the below conditions :
If a player has multiple client_names or multiple client_country, then select the record which has the maximum value of rating . If it is negavie, then take the absolute value of that value. i.e if the rating is -10 and -34, then take the absolute value which is greatest. i. e by taking absolute value it is 10,34 and 34 is greatest one.
For ex: Kumar has 3 diff client names or 3 diff client_country ,so for kumar the record with rating 32 should be selected ,after taking the absolute value of it.
Below is the expected output:
Player_NAME || Player_NUMBER ||Client_name || Client_country ||Player_country|| Rating
GERALD || A1234 || BENFIELD|| IND|| IND|| 76
KUMAR || P5678 || JEURASIN ||ARG ||TUR || -32
ANDREW || R1234 || GENMAD ||GER ||GER || 23
destination table-'table2'
You can try something like this:
INSERT INTO Table2
(
Player_Name,
Player_Number,
Cliet_Name,
Client_country,
Player_country,
Rating
)
SELECT
Player_Name,
Player_Number,
Cliet_Name,
Client_country,
Player_country,
MAX(ABS(Rating)) OVER (PARTITION BY player_Name ORDER BY Cliet_Name,
Client_country) as Rating
FROM
table1
If your DBMS supports Analytical Function you can utilize ROW_NUMBER:
select ... -- all columns but rn
from
(
select ... -- all columns
,row_number()
over (partition by player_name
order by abs(Rating) desc as rn
from table1
) as dt
where rn = 1;
Otherwise use a Correlated Subquery:
select *
from table1 as t1
where abs(rating) =
( select max(abs(rating))
from table1 as t2
where t1.player_name = t2.player_name
)
If you got multiple rows with the same max(abs(rating)) #1. will select one of them randomly, but #2 will select all.
I guess, this query will work:
select
max(abs(Rating))
from Table1
group by Player_NAME
To insert data into Table2, you can do it like so:
INSERT INTO Table2 (
Player_Name,
Player_Number,
Cliet_Name,
Client_country,
Player_country,
Rating
)
SELECT
t1.Player_Name,
t1.Player_Number,
t1.Cliet_Name,
t1.Client_country,
t1.Player_country,
t1.Rating
FROM Table1 t1
INNER JOIN (
SELECT
Player_NAME,
MAX(ABS(Rating)) as Rating
FROM Table1
GROUP BY Player_NAME
) t2 ON t2.Player_NAME = t1.Player_NAME AND ABS(t1.Rating) = t2.Rating

Convert row data to new columns based on common ID value

I have an MS Access database for product ID list for each client ID.
Currently, the table is set up as the following:
CLI_ID || PRODUCT_ID
963506 || 49001608
968286 || 49001645
987218 || 00048038
987218 || 49001401
999999 || 9999999
999999 || 9999998
999999 || 9999997
999999 || 9999996
I would like to transpose the data to look like this:
CLI_ID || PRODUC1 || PRODUC2 || PRODUC3 || PRODUC4 ||
963506 || 49001608 ||
968286 || 49001645 ||
987218 || 00048038 || 49001401 ||
999999 || 99999999 || 99999998 || 99999997 || 99999996 ||
There are clients with more products than 4 in the example shown above so I would like the query to be expandable by counting # of product IDs in each client ID.
I took the code from ChrisPadgham's post and modified it to meet my needs...Here is what I have so far but it is not going further than PRODUC1:
TRANSFORM Last([PRODUCT_ID]) AS Details
SELECT Source_Table.CLI_ID
FROM Source_Table
GROUP BY Source_Table.CLI_ID
PIVOT "PRODUC" & (DCount("[PRODUCT_ID]","[Source_Table]", "[PRODUCT_ID]<>" &
[PRODUCT_ID] & " AND [CLI_ID]=" & [CLI_ID]) +1);
Any help would be appreciated!
Try adding a per client item counter to your data. Examples Found Here
It looks like your going to need to create a temp table as Access can't keep track of internal pointers when nesting the queries.
Create a temp table:
SELECT t1.CLI_ID, t1.PRODUCT_ID, (SELECT COUNT(*)
FROM Source_Table t2
WHERE t2.CLI_ID = t1.CLI_ID
AND t2.PRODUCT_ID <= t1.PRODUCT_ID
) AS PROD_COUNT INTO TEMP_CLI_PROD
FROM Source_Table AS t1
GROUP BY t1.CLI_ID, t1.PRODUCT_ID;
Then have your pivot table reference the temp table.
TRANSFORM Last(TEMP_CLI_PROD.PRODUCT_ID) AS LastOfPRODUCT_ID
SELECT TEMP_CLI_PROD.CLI_ID
FROM TEMP_CLI_PROD
GROUP BY TEMP_CLI_PROD.CLI_ID
PIVOT "PRODUCT " & TEMP_CLI_PROD.PROD_COUNT;
Output:
CLI_ID PRODUCT 1 PRODUCT 2 PRODUCT 3 PRODUCT 4
963506 49001608
968286 49001645
987218 00048038 49001401
999999 9999996 9999997 9999998 9999999
Jeff's answer is essentially correct in its approach, although a temporary table is not strictly required:
TRANSFORM First(PRODUCT_ID) AS whatever
SELECT CLI_ID
FROM
(
SELECT t1.CLI_ID, t1.PRODUCT_ID, 'PRODUCT_' & COUNT(*) AS XtabColumn
FROM
Source_Table AS t1
INNER JOIN
Source_Table AS t2
ON t1.CLI_ID = t2.CLI_ID
AND t1.PRODUCT_ID >= t2.PRODUCT_ID
GROUP BY t1.CLI_ID, t1.PRODUCT_ID
)
GROUP BY CLI_ID
PIVOT XtabColumn
returns
CLI_ID PRODUCT_1 PRODUCT_2 PRODUCT_3 PRODUCT_4
------ --------- --------- --------- ---------
963506 49001608
968286 49001645
987218 00048038 49001401
999999 9999996 9999997 9999998 9999999

Query on a AS tablename in Oracle 10g

Hey all, how can i go about query off a made AS Tablename in a query of mine?
(its a long query so i have shortened it to the needed lines for this example)
SELECT
TO_CHAR(SYSDATE, 'YYYYMMDD') AS CURDATE,
TO_CHAR(A.DUE_DATE, 'YYYYMMDD') AS DUE,
UGRP.GROUP_CODE AS UGRPCODE,
A.DETAILS,
TRIM(STF.IDENTIFIER_1) || ', ' || TRIM(STF.IDENTIFIER_2) || ' ' || TRIM(STF.IDENTIFIER_3) AS STAFF,
FROM REC.CUSTOM_ATTRIBUTES E
INNER JOIN REC.SERVICE_REQUESTS SR
INNER JOIN REC.IDENTIFIERS STF ON A.ASSIGNED_STAFF_EID = STF.OWNER_EID ON E.OWNER_EID = SR.EID
WHERE (TYP.TYPE_CODE = 'SRSRTYPE')
AND (A.ASSIGNED_STAFF_EID <> 2000478)
AND STAFF = 'BARKER, BOB'
ORDER BY SR.SERVICE_REQUEST_NUM
Naturally the AND STAFF = 'BARKER, BOB" will not work for me.
My question is how can I query on that column?
Thanks!
David
Repeat the formula in your WHERE clause.
... AND TRIM(STF.IDENTIFIER_1) || ', ' || TRIM(STF.IDENTIFIER_2) || ' ' || TRIM(STF.IDENTIFIER_3) = 'BARKER, BOB' ...