I have a table with columns number, name, address & contact, i want to display unique in a row like say
number , name, address, contact
1 , joy, Elgin , Obere Str. 57
2 , saf, Berlin ,Obere Str. 57
3 , andy, Berlin, Avda. de la ConstituciĆ³n 2222
3 , rin, Berlin ,Mataderos 2312
Display like this
number , name, address, contact
1 , joy, Elgin , Obere Str. 57
2 , saf, Berlin ,Obere Str. 57
3 , andy, Berlin, Avda. de la ConstituciĆ³n 2222
How ?
Most databases support the ANSI-standard row_number() function. You can do this as:
select t.*
from (select t.*,
row_number() over (partition by number order by number) as seqnum
from table t
) t
where seqnum = 1;
Note: this chooses an arbitrary row from matching numbers, which seems entirely consistent with the phrasing of the question.
select min(number),name,address, contact from tableName where status='p' group by number
select distinct number , name, address, contact
order by id;
Related
I have a table that looks like this:
City_Id
City
41
Athena
39
Beijing
35
London
30
Rio de Janeiro
28
Salt Lake City
18
Sochi
7
Sydney
4
Torino
is there a way to display another row in the bottom that will display the total count of rows?
City_Id
City
41
Athena
39
Beijing
35
London
30
Rio de Janeiro
28
Salt Lake City
18
Sochi
7
Sydney
4
Torino
Total
8
You can actually use GROUPING SETS for this. This avoids having to scan the table twice.
However you still have the data-type mismatch problem. You could solve it by casting, but it's probably easier to just swap the columns around
SELECT
CASE WHEN GROUPING(City) = 0 THEN City ELSE 'Total' END AS City,
CASE WHEN GROUPING(City_Id) = 0 THEN City_Id ELSE COUNT(*) END AS City_Id
FROM Table1
GROUP BY GROUPING SETS (
(City_Id, City),
()
)
ORDER BY GROUPING(City_Id);
SQL Fiddle
What this does is generate separate result-sets, unioned together. You can differentiate between a grouped row and a non-grouped row using the GROUPING function.
I would agree with most of the other comments that acquiring a result set count would be more appropriate from the application code (which usually has a mechanism specifically for this purpose).
However...
If you must have a TSQL solution for your question, an option is to return the count in a separate column. This is different than returning it in a separate row, of course. There are pros & cons with each approach.
DROP TABLE IF EXISTS #Cities;
CREATE TABLE #Cities (
City_Id INT,
City VARCHAR(128)
);
INSERT INTO #Cities
VALUES
(41, 'Athena'),
(39, 'Beijing'),
(35, 'London'),
(30, 'Rio de Janeiro'),
(28, 'Salt Lake City'),
(18, 'Sochi'),
(7 , 'Sydney'),
(4 , 'Torino');
SELECT *, COUNT(*) OVER(ORDER BY (SELECT NULL)) AS Total
FROM #Cities;
--Count is properly reflected based on WHERE clause.
SELECT *, COUNT(*) OVER(ORDER BY (SELECT NULL)) AS Total
FROM #Cities
WHERE City LIKE 'S%';
--Be careful with this one--the COUNT(*) may not be what you expected.
SELECT TOP(4) *, COUNT(*) OVER(ORDER BY (SELECT NULL)) AS Total
FROM #Cities;
NOTE: be aware that this approach may not scale (perform) well for large result sets. Be sure to do some testing!
As you know already, it should be done in the presentation layer. But if you just want to know if there is any way, then I would suggest to use UNION ALL
select cast(City_Id as varchar(10)) City_Id, City from Table1
union all
select 'Total' as City_Id, cast(count(*) as varchar(14)) from Table1
Here is the sql fiddle
I have a table that lists my volunteers and a column for the number of postcards they've decided to write. I'm trying to return a row that creates a row assigning each volunteer to a postcard based on how many the requested.
For example, if volunteer A requested 3 postcards, volunteer B, 1 postcard, and volunteer C requested 2 postcards, then I'd want my query to return something like this:
rowNumber
volunteer
postcardsAssigned
1
Volunteer A
1
2
Volunteer A
2
3
Volunteer A
3
4
Volunteer B
4
5
Volunteer C
5
6
Volunteer C
6
Attached a picture below that shows what my current query results in and what I'm trying to get it to look like.
With postcards_vols as (SELECT What_s_your_name_ as Name
, What_s_your_email_ as Email
, What_s_your_phone_number_ as Phonenumber
, Mailing_Street_Address as StreetAddress
, Mailing_City as City
, Mailing_Zip_code as Zip
, Mailing_State as State
, How_many_cards_would_you_like_us_to_send_ as Postcards_Requested
, ROW_NUMBER() OVER() AS Request_Number
, Submitted_At as date_requested
FROM volunteer_program.postcard_volunteers)
SELECT *
, SUM (Postcards_requested) OVER (PARTITION BY request_number, date_requested ORDER BY date_requested DESC) AS addresses_assigned,
FROM
postcards_vols
[Current Query Output and Sample Desired Query Output][1]
[1]: https://i.stack.imgur.com/dGssK.png
* Names and address shown in the picture are fictitious
You can generate the extra rows you want using arrays and then unnesting:
select pv.*, num,
row_number() over (order by volunteer, num) as postcardsassigned
from `postcards_vols` pv cross join
unnest(generate_array(1, pv.request_number)) num;
num is an enumeration within each volunteer.
Thanks! I hadn't used a cross join in a minute.
This seemed to do the trick.
with postcards_vols as (SELECT What_s_your_name_ as Name
, What_s_your_email_ as Email
, What_s_your_phone_number_ as Phonenumber
, Mailing_Street_Address as StreetAddress
, Mailing_City as City
, Mailing_Zip_code as Zip
, Mailing_State as State
, How_many_cards_would_you_like_us_to_send_ as Postcards_Requested
, ROW_NUMBER() OVER() AS Request_Number
, Submitted_At as date_requested
FROM `noble-hangar-313121.volunteer_program.postcard_volunteers`),
distribution AS (
SELECT pv.*, num,
row_number() OVER (ORDER BY name, num) AS postcardsassigned
FROM `postcards_vols` pv CROSS JOIN
unnest(generate_array(1, pv.Postcards_Requested)) num
)
SELECT request_number as packet_number
, Name as volunteer_name
, Email as volunteer_email
, Phonenumber as volunteer_phone
, StreetAddress as volunteer_streetAddress
, City as volunteer_city
, Zip as volunteer_zip
, State as volunteer_state
, Address as postcard_address
, city_State as postcard_citystate
, zipcode as postcard_zipcode
FROM
distribution d
LEFT JOIN
field_report.postcard_address_distribution
ON number = postcardsassigned
GROUP BY request_number, 1, 2,3,4,5,6,7, 8, 9, 10, 11
ORDER BY packet_number
I have created a simple Access database an example of table structure and a query. Two tables, person(contains 3 records) & address(contains 5 records), provide the ability to capture multiple addresses for each person. I am good with normal conditional statements, but this one is throwing me for a loop...
I am looking for a query that will return only the newest address for a given person.
Table Relationship
Current sql for the query:
SELECT Person.PersonID_PK, Address.Address, Address.StatusDate
FROM Person INNER JOIN Address ON Person.[PersonID_PK] = Address.PersonID_FK;
My current returns:
EmployeeID_PK Address StatusDate
1 12 Elm St, MN 23569 11/13/2017
1 15 Apple Ln, NY 12345 7/15/2018
2 30 Mulberry, TN 38456 6/11/2018
2 10 Lonesome Pine, KY 15487 12/4/2018
3 100 Plaze Place, LA 14563 6/17/2018
I need to return each person along with the greatest(newest) StatusDate
My expected return should be:
EmployeeID_PK Address StatusDate
1 15 Apple Ln, NY 12345 7/15/2018
2 10 Lonesome Pine, KY 15487 12/4/2018
3 100 Plaze Place, LA 14563 6/17/2018
You can use a correlated subquery:
select a.*
from address as a
where a.statusdate = (select max(a2.statusdate)
from address as a2
where a2.EmployeeID_PK = a.EmployeeID_PK
);
Using a CTE with a ranking function works neatly.
;WITH empaddress AS
(
SELECT person.personid_pk,
address.address,
address.statusdate,
Dense_rank() OVER (partition BY id ORDER BY statusdate DESC) AS d_rank
FROM person
INNER JOIN address
ON person.[PersonID_PK] = address.personid_fk; )
SELECT person.personid_pk,
address.address,
address.statusdate
FROM empaddress
WHERE d_rank = 1;
Thanks for the help. I modified Gordon's code to support my query, the following provided the answer.
SELECT Person.PersonID_PK, Address.Address, Address.StatusDate
FROM Person
INNER JOIN Address
ON Person.[PersonID_PK] = Address.PersonID_FK
WHERE (((Address.StatusDate)=(SELECT MAX(Address.StatusDate)
FROM Address
WHERE Person.PersonID_PK = Address.PersonID_FK)));
How can I select distinct one column (user) and then output the rest of the fields based on this one column?
Input:
user age country
--------------------------------
Tom 34 US
Tom 32 EN
Dick 29 MX
Dick 29 DE
Harry 15 CA
output (distinct user column, and pick one row to output for rest of fields):
user age country count
--------------------------------------
Tom 34 US 2
Dick 29 MX 2
Harry 15 CA 1
Any help would be appreciated!
SELECT USER, AGE, MAX(COUNTRY), COUNT(*)
FROM TABLE
GROUP BY USER, AGE
You could try changing the MAX for a MIN. No need for a DISTINCT here.
You could use some data format like SUBSTRING, but I'm not sure if the rest of the data will always be like that US and USS etc. Buy if you have more than 2/3 or if the changes start beyond a specific character you may encounter some wrong query results.
According to comments and updates.
SELECT USER, MAX(AGE), MAX(COUNTRY), COUNT(*)
FROM TABLE
GROUP BY USER.
SELECT user, age, country, COUNT(*) AS c_rec FROM
(
SELECT DISTINCT user, age, SUBSTRING(country, 1, 2) AS country FROM yourTable
) T
GROUP BY user, age, country
In a program I'm maintaining we were given a massive (~500 lines) SQL statement by the customer. It is used for generating flat files with fixed length records for transmitting data to another big business. Since its a massive flat file its not relational and the standard normal forms of data are collapsed. So, if you have a record that can have multiple codes associated, in this case upto 19, they all have be written into single line, but seperate fields, in the flat file.
Note: this example is simplified.
The data might look like this, with three tables:
RECORDS
record_id firstname lastname
--------------------------------
123 Bob Schmidt
324 George Washington
325 Ronald Reagan
290 George Clooney
CODE_TABLE
code_id code_cd code_txt
--------------------------------
5 3 President
2 4 Actor
3 7 Plumber
CODES_FOR_RECORDS
record_id code_cd
-------------------
123 7
325 3
290 4
324 3
325 4
123 4
This needs to produce records like:
firstname lastname code1 code2 code3
Bob Schmidt Actor Plumber NULL
George Washington President NULL NULL
Ronald Reagon Actor President NULL
George Clooney Actor NULL NULL
The portion of the current query we were given looks like this, but with 19 code columns instead of the 5:
select
x.record_id,
max(case when x.rankk = 1 then code_txt end) as CodeColumn1,
max(case when x.rankk = 2 then code_txt end) as CodeColumn2,
max(case when x.rankk = 3 then code_txt end) as CodeColumn3,
max(case when x.rankk = 4 then code_txt end) as CodeColumn4,
max(case when x.rankk = 5 then code_txt end) as CodeColumn5,
from
(
select
r.record_id,
ct.code_txt as ctag ,
dense_rank() over (partition by r.record_id order by cfr.code_id) as rankk
from
records as r
codes_for_records as cfr,
code_table as ct
where
r.record_id = cfr.record_id
and ct.code_cd = cfr.code_cd
and cfr.code_cd is not null
and ct.code_txt not like '%V%'
) as x
where
x.record_id is not null
group by
x.record_id
I trimmed down things for simplicties sake, but the actual statment includes an inner query and a join and more where conditions, but that should get the idea across. My brain is telling me there has to be a better way, but I'm not an SQL expert. We are using DB2 v8 if that helps. And the codes have to be in seperate columns, so no coalescing things into a single string. Is there a cleaner solution than this?
Update:
I ended up just refacorting the original query, it sill uses the ugly MAX() business, but overall the query is much more readable due to reworking other parts.
It sounds like what you are looking for is pivoting.
WITH joined_table(firstname, lastname, code_txt, rankk) AS
(
SELECT
r.firstname,
r.lastname,
ct.code_txt,
dense_rank() over (partition by r.record_id order by cfr.code_id) as rankk
FROM
records r
INNER JOIN
codes_for_records cfr
ON r.record_id = cfr.record_id
INNER JOIN
codes_table ct
ON ct.code_cd = cfr.code_cd
),
decoded_table(firstname, lastname,
CodeColumn1, CodeColumn2, CodeColumn3, CodeColumn4, CodeColumn5) AS
(
SELECT
firstname,
lastname,
DECODE(rankk, 1, code_txt),
DECODE(rankk, 2, code_txt),
DECODE(rankk, 3, code_txt),
DECODE(rankk, 4, code_txt),
DECODE(rankk, 5, code_txt)
FROM
joined_table jt
)
SELECT
firstname,
lastname,
MAX(CodeColumn1),
MAX(CodeColumn2),
MAX(CodeColumn3),
MAX(CodeColumn4),
MAX(CodeColumn5)
FROM
decoded_table dt
GROUP BY
firstname,
lastname;
Note that I've never actually done this myself before. I'm relying on the linked document as a reference.
You might need to include the record_id to account for duplicate names.
Edit: Added the GROUP BY.
One of the possible solutions is using of recursive query:
with recursive_view (record_id, rankk, final) as
(
select
record_id,
rankk,
cast (ctag as varchar (100))
from inner_query t1
union all
select
t1.record_id,
t1.rankk,
/* all formatting here */
cast (t2.final || ',' || t1.ctag as varchar (100))
from
inner_query t1,
recursive_view t2
where
t2.rankk < t1.rankk
and t1.record_id = t2.record_id
and locate(t1.ctag, t2.final) = 0
)
select record_id, final from recursive_view;
Can't guarantee that it works, but hope it will be helpful. Another way is using of custom aggregate function.