3

Hi I know how to use the group by clause for sql. I am not sure how to explain this so Ill draw some charts. Here is my original data:

Name Location ---------------------- user1 1 user1 9 user1 3 user2 1 user2 10 user3 97 

Here is the output I need

Name Location ---------------------- user1 1 9 3 user2 1 10 user3 97 

Is this even possible?

5
  • 6
    What you're looking for is a way to prettify the presentation of the data. That's not what SQL is for. Commented May 9, 2012 at 19:42
  • I am doing this for a report to submit to management. Commented May 9, 2012 at 19:44
  • Yes, it is possible. Check out the SQL Cookbook, which tells how to do this. Warning: complicated. Commented May 9, 2012 at 19:44
  • 1
    @Luke101 Don't do it with a straight output from SQL. Do it in Excel or something similar, which can easily use SQL as a datasource. Commented May 9, 2012 at 19:45
  • Then give them the report in Excel or add some other layer to prettify the data. That's not what an RDBMS is for. Commented May 9, 2012 at 19:45

7 Answers 7

4

The normal method for this is to handle it in the presentation layer, not the database layer.

Reasons:

  • The Name field is a property of that data row
  • If you leave the Name out, how do you know what Location goes with which name?
  • You are implicitly relying on the order of the data, which in SQL is a very bad practice (since there is no inherent ordering to the returned data)
  • Any solution will need to involve a cursor or a loop, which is not what SQL is optimized for - it likes working in SETS not on individual rows
Sign up to request clarification or add additional context in comments.

Comments

3

Hope this helps

 SELECT A.FINAL_NAME, A.LOCATION FROM (SELECT DISTINCT DECODE((LAG(YT.NAME, 1) OVER(ORDER BY YT.NAME)), YT.NAME, NULL, YT.NAME) AS FINAL_NAME, YT.NAME, YT.LOCATION FROM YOUR_TABLE_7 YT) A 

As Jirka correctly pointed out, I was using the Outer select, distinct and raw Name unnecessarily. My mistake was that as I used DISTINCT , I got the resulted sorted like

 1 1 2 user2 1 3 user3 97 4 user1 1 5 3 6 9 7 10 

I wanted to avoid output like this.

Hence I added the raw id and outer select

However , removing the DISTINCT solves the problem. Hence only this much is enough

 SELECT DECODE((LAG(YT.NAME, 1) OVER(ORDER BY YT.NAME)), YT.NAME, NULL, YT.NAME) AS FINAL_NAME, YT.LOCATION FROM SO_BUFFER_TABLE_7 YT 

Thanks Jirka

2 Comments

I totally forgot about windowing functions
Beautiful. Why not to remove the outer SELECT, the inner DISTINCT, and the raw YT.NAME from the select list? I would expect an equivalent result.
2

If you're using straight SQL*Plus to make your report (don't laugh, you can do some pretty cool stuff with it), you can do this with the BREAK command:

SQL> break on name SQL> WITH q AS ( SELECT 'user1' NAME, 1 LOCATION FROM dual UNION ALL SELECT 'user1', 9 FROM dual UNION ALL SELECT 'user1', 3 FROM dual UNION ALL SELECT 'user2', 1 FROM dual UNION ALL SELECT 'user2', 10 FROM dual UNION ALL SELECT 'user3', 97 FROM dual ) SELECT NAME,LOCATION FROM q ORDER BY name; NAME LOCATION ----- ---------- user1 1 9 3 user2 1 10 user3 97 6 rows selected. SQL> 

Comments

1

I cannot but agree with the other commenters that this kind of problem does not look like it should ever be solved using SQL, but let us face it anyway.

SELECT CASE main.name WHERE preceding_id IS NULL THEN main.name ELSE null END, main.location FROM mytable main LEFT JOIN mytable preceding ON main.name = preceding.name AND MIN(preceding.id) < main.id GROUP BY main.id, main.name, main.location, preceding.name ORDER BY main.id 

The GROUP BY clause is not responsible for the grouping job, at least not directly. In the first approximation, an outer join to the same table (LEFT JOIN below) can be used to determine on which row a particular value occurs for the first time. This is what we are after. This assumes that there are some unique id values that make it possible to arbitrarily order all the records. (The ORDER BY clause does NOT do this; it orders the output, not the input of the whole computation, but it is still necessary to make sure that the output is presented correctly, because the remaining SQL does not imply any particular order of processing.)

As you can see, there is still a GROUP BY clause in the SQL, but with a perhaps unexpected purpose. Its job is to "undo" a side effect of the LEFT JOIN, which is duplication of all main records that have many "preceding" ( = successfully joined) records.

This is quite normal with GROUP BY. The typical effect of a GROUP BY clause is a reduction of the number of records; and impossibility to query or test columns NOT listed in the GROUP BY clause, except through aggregate functions like COUNT, MIN, MAX, or SUM. This is because these columns really represent "groups of values" due to the GROUP BY, not just specific values.

1 Comment

Thank you..I had to tweak the query a little but it works now. I appreciate you guiding me in the right direction.
1

If you are using SQL*Plus, use the BREAK function. In this case, break on NAME.

If you are using another reporting tool, you may be able to compare the "name" field to the previous record and suppress printing when they are equal.

Comments

1

If you use GROUP BY, output rows are sorted according to the GROUP BY columns as if you had an ORDER BY for the same columns. To avoid the overhead of sorting that GROUP BY produces, add ORDER BY NULL:

SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL; 

Relying on implicit GROUP BY sorting in MySQL 5.6 is deprecated. To achieve a specific sort order of grouped results, it is preferable to use an explicit ORDER BY clause. GROUP BY sorting is a MySQL extension that may change in a future release; for example, to make it possible for the optimizer to order groupings in whatever manner it deems most efficient and to avoid the sorting overhead.

For full information - http://academy.comingweek.com/sql-groupby-clause/

Comments

0

SQL GROUP BY STATEMENT SQL GROUP BY clause is used in collaboration with the SELECT statement to arrange identical data into groups. Syntax: 1. SELECT column_nm, aggregate_function(column_nm) FROM table_nm WHERE column_nm operator value GROUP BY column_nm; Example : To understand the GROUP BY clauserefer the sample database.Below table showing fields from “order” table: 1. |EMPORD_ID|employee1ID|customerID|shippers_ID|

Below table showing fields from “shipper” table: 1. | shippers_ID| shippers_Name |

Below table showing fields from “table_emp1” table: 1. | employee1ID| first1_nm | last1_nm |

Example : To find the number of orders sent by each shipper. 1. SELECT shipper.shippers_Name, COUNT (orders.EMPORD_ID) AS No_of_orders FROM orders LEFT JOIN shipper ON orders.shippers_ID = shipper.shippers_ID GROUP BY shippers_Name; 1. | shippers_Name | No_of_orders | Example : To use GROUP BY statement on more than one column. 1. SELECT shipper.shippers_Name, table_emp1.last1_nm, COUNT (orders.EMPORD_ID) AS No_of_orders FROM ((orders INNER JOIN shipper ON orders.shippers_ID=shipper.shippers_ID) INNER JOIN table_emp1 ON orders.employee1ID = table_emp1.employee1ID) 2. GROUP BY shippers_Name,last1_nm;

  1. | shippers_Name | last1_nm |No_of_orders |

for more clarification refer my link http://academy.comingweek.com/sql-groupby-clause/

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.