Select 2 distinct columns in 4GL - sql

Needed for my 4gl program:
Let's say I have a table that holds a phone number and a name. There can be 2 people with the same phone number, or 2 names with 1 phone number.
I need to select just 1 of each phone number in the table.
I did:
SELECT DISTINCT phone_number, last_name FROM table
The results will show 2 records. Even phone number is the same, since the names are different it is no longer unique. How can I get a unique phone number regardless of its last_name? (But I want to get the last name as well. I don't care which one)

DISTINCT, as you've noticed, will return rows that are distinct in their entirety.
It sounds like you're looking for something like group by. Essentially, GROUP BY phone_number will return one row for each phone number. Because you also want to get last_name, you'll need to instruct the database how you want it to be returned. You said you don't care which so you could simply write:
SELECT phone_number, MAX(last_name) as last_name
FROM table
GROUP BY phone_number
Informix also supports a FIRST_VALUE aggregate function although I've only used that in OLAP situations so I don't recall if it will work in this context.

If you don't care which last name, then try this out:
SELECT phone_number,
MAX(last_name) AS last_name
FROM table
GROUP BY phone_number

Related

Count how many employees with the same name exist in the database in PostgreSQL

I have a data table of employees, I want to get how many same name employees in the database. Name information is saved as first_name and last_name. I have tried.
Select count(concat(first_name,'',last_name) as empname, (concat(first_name,'',last_name) as empname from xyz.
getting error.
Your SQL is missing some parentheses (brackets), and to use an aggregation function as well as a non-aggregated column, you must include the non-aggregated column in a GROUP BY
So your SQL should look like this:
Select count(concat(first_name,' ',last_name)) as countempname,
(concat(first_name,' ',last_name)) as empname
from xyz
GROUP BY (concat(first_name,' ',last_name));
Notice also that I added a space. It is a bit odd to include an empty string in the concat. Also as a short form, if you do not want to repeat the concat in the GROUP BY, you can replace it with the column ordinal number (in this case 2) so it becomes:
Select count(concat(first_name,' ',last_name)) as countempname,
(concat(first_name,' ',last_name)) as empname
from xyz
GROUP BY 2;
If you want to count how many times each first/last name tuple appears in the table, you can use aggregation:
select first_name, last_name, count(*) cnt
from xyz
group by first_name, last_name
This gives you one row per first/last name tuple, with the total count. Note that there is not point concatenating the variables; group by can operate of column tuples.
On the other hand, maybe you want the entire employee row, with an additional column that holds the total count of other rows having the same names. If so, you can use a window count instead of aggregation:
select x.*, count(*) over(partiton by first_name, last_name) cnt
from xyz

In one query, get length of last name, length of first name and group by lengths - three columns

I'm a noob...and working on a homework problem.
Have a members table with last_name, first_name. I want to write one query that aggregates the length of last_name, first_name by string length.
The output would have three columns - name_length, count_of_last_names, count_of_first_names.
Two individual queries:
`SELECT LENGTH(last_name) AS "LnameLen", COUNT(LENGTH(last_name)) AS "CntLnameLen"
FROM members
GROUP BY LENGTH(last_name)
ORDER BY "LnameLen" DESC;
SELECT LENGTH(first_name) AS "FnameLen", COUNT(LENGTH(first_name)) AS "CntFnameLen"
FROM members
GROUP BY LENGTH(first_name)
ORDER BY "FnameLen";`
But I want to write one query that outputs what the above two queries do, so the output would be three columns: Length_of_Name, CntLnameLen, CntFnameLen.
Suggestions? Thanks!
The way I understood the question, something like this might be what you're looking for.
select length(first_name),
length(last_name),
count(*)
from members
group by length(first_name),
length(last_name);

How to insert a count column into a sql query

I need the second column of the table retrieved from a query to have a count of the number of rows, so row one would have a 1, row 2 would have a 2 and so on. I am not very proficient with sql so I am sorry if this is a simple task.
A basic example of what I am doing would be is:
SELECT [Name], [I_NEED_ROW_COUNT_HERE],[Age],[Gender]
FROM [customer]
The row count must be the second column and will act as an ID for each row. It must be the second row as the text file it is generating will be sent to the state and they require a specific format.
Thanks for any help.
With your edit, I see that you want a row ID (normally called row number rather than "count") which is best gathered from a unique ID in the database (person_id or some other unique field). If that isn't possible, you can make one for this report with ROW_NUMBER() OVER (ORDER BY EMPLOYEE_ID DESC) AS ID, in your select statement.
select Name, ROW_NUMBER() OVER (ORDER BY Name DESC) AS ID,
Age, Gender
from customer
This function adds a field to the output called ID (see my tips at the bottom to describe aliases). Since this isn't in the database, it needs a method to determine how it will increment. After the over keyword it orders by Name in descending order.
Information on Counting follows (won't be unique by row):
If each customer has multiple entries but the selected fields are the same for that user and you are counting that user's records (summed in one result record for the user) then you would write:
select Name, count(*), Age, Gender
from customer
group by name, age, gender
This will count (see MSDN) all the user's records as grouped by the name, age and gender (if they match, it's a single record).
However, if you are counting all records so that your whole report has the grand total on every line, then you want:
select Name, (select count(*) from customer) as "count", Age, Gender
from customer
TIP: If you're using something like SSMS to write a query, dragging in columns will put brackets around the columns. This is only necessary if you have spaces in column names, but a DBA will tend to avoid that like the plague. Also, if you need a column header to be something specific, you can use the as keyword like in my first example.
W3Schools has a good tutorial on count()
The COUNT(column_name) function returns
the number of values (NULL values will not be counted) of the
specified column:
SELECT COUNT(column_name) FROM table_name;
The COUNT(*) function returns the number of records in a table:
SELECT COUNT(*) FROM table_name;
The COUNT(DISTINCT column_name) function returns the number of
distinct values of the specified column:
SELECT COUNT(DISTINCT column_name) FROM table_name;
COUNT(DISTINCT) works with ORACLE and Microsoft SQL Server, but
not with Microsoft Access.
It's odd to repeat the same number in every row but it sounds like this is what you're asking for. And note that this might not work in your flavor of SQL. MS Access?
SELECT [Name], (select count(*) from [customer]), [Age], [Gender]
FROM [customer]

Geting value count from an Oracle Table

I have a table, that contains employees. Since the company I'm working for is quite big (>3k employees) It is only natural, that some of them have the same names. Now they can be differentiated by their usernames, but since a webpage needs a drop-down with all of these users, I need to add some extra data to their names.
I know I could first grab all of the users and then run them through a foreach and add a count to each of the user objects. That would be quite ineffective though. Therefore I'm in need of a good SQL query, that would do something like this. Could a sub-query be the thing I need?
My Table looks something like this:
name ----- surname ----- username
John Mayer jmaye
Suzan Harvey sharv
John Mayer jmay3
Now what I think would be great, if the query returned the same 3 fields and also a boolean if there is more than one person with the same name and surname combination.
Adding the flag to Daniel's answer...
SELECT NAME, SURNAME, USERNAME, DECODE(COUNT(*) OVER (PARTITION BY NAME, SURNAME), 1, 'N', 'Y')
FROM
YOUR_TABLE;
Please note that Oracle SQL has no support for booleans (sigh...)
This can be easily done with a count over partition:
SELECT NAME, SURNAME, USERNAME, COUNT(*) OVER (PARTITION BY NAME, SURNAME)
FROM
YOUR_TABLE;

Return all Fields and Distinct Rows

Whats the best way to do this, when looking for distinct rows?
SELECT DISTINCT name, address
FROM table;
I still want to return all fields, ie address1, city etc but not include them in the DISTINCT row check.
Then you have to decide what to do when there are multiple rows with the same value for the column you want the distinct check to check against, but with different val;ues in the other columns. In this case how does the query processor know which of the multiple values in the other columns to output, if you don't care, then just write a group by on the distinct column, with Min(), or Max() on all the other ones..
EDIT: I agree with comments from others that as long as you have multiple dependant columns in the same table (e.g., Address1, Address2, City, State ) That this approach is going to give you mixed (and therefore inconsistent ) results. If each column attribute in the table is independant ( if addresses are all in an Address Table and only an AddressId is in this table) then it's not as significant an issue... cause at least all the columns from a join to the Address table will generate datea for the same address, but you are still getting a more or less random selection of one of the set of multiple addresses...
This will not mix and match your city, state, etc. and should give you the last one added even:
select b.*
from (
select max(id) id, Name, Address
from table a
group by Name, Address) as a
inner join table b
on a.id = b.id
When you have a mixed set of fields, some of which you want to be DISTINCT and others that you just want to appear, you require an aggregate query rather than DISTINCT. DISTINCT is only for returning single copies of identical fieldsets. Something like this might work:
SELECT name,
GROUP_CONCAT(DISTINCT address) AS addresses,
GROUP_CONCAT(DISTINCT city) AS cities
FROM the_table
GROUP BY name;
The above will get one row for each name. addresses contains a comma delimted string of all the addresses for that name once. cities does the sames for all the cities.
However, I don't see how the results of this query are going to be useful. It will be impossible to tell which address belongs to which city.
If, as is often the case, you are trying to create a query that will output rows in the format you require for presentation, you're much better off accepting multiple rows and then processing the query results in your application layer.
I don't think you can do this because it doesn't really make sense.
name | address | city | etc...
abc | 123 | def | ...
abc | 123 | hij | ...
if you were to include city, but not have it as part of the distinct clause, the value of city would be unpredictable unless you did something like Max(city).
You can do
SELECT DISTINCT Name, Address, Max (Address1), Max (City)
FROM table
Use #JBrooks answer below. He has a better answer.
Return all Fields and Distinct Rows
If you're using SQL Server 2005 or above you can use the RowNumber function. This will get you the row with the lowest ID for each name. If you want to 'group' by more columns, add them in the PARTITION BY section of the RowNumber.
SELECT id, Name, Address, ...
(select id, Name, Address, ...,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY id) AS RowNo
from table) sub
WHERE RowNo = 1