I need to combine two values from different rows and sum the count value associate with them
I have:
Name
Number(count)
Paul
50
John
50
i need
Name
Number(count)
paul/john
100
How can I make this work with in SQL?
Two aggregates.
Sample data:
SQL> with test (name, count) as
2 (select 'Paul', 50 from dual union all
3 select 'John', 50 from dual
4 )
Query:
5 select listagg(name, '/') within group (order by null) name,
6 sum(count) sum_count
7 from test;
NAME SUM_COUNT
-------------------- ----------
Paul/John 100
SQL>
Related
My Table:
ID NAME
1 SIVA
2 RAJA
3 PYTHON
4 SQL
5 ODI
I need to lead by 3 rows.
My SQL Query:
SELECT LEAD(NAME,3) OVER (ORDER by NAME) as NAME FROM TEST_TABLE where NAME='SIVA'
EXPECTED OUTPUT:
--------
| NAME |
--------
| SQL |
--------
Example:
If I pass value as SIVA, then I need to get SQL as output.
Similarly if I pass value as Raja, then I need to get ODI as output
Is there any query to get the expected output?
This might be one option: it uses row_number analytic function which calculates row numbers so that you wouldn't have to rely on ID values. What if they are acquired by a sequence? It is not gapless. Basically - it is used for safety.
SQL> WITH test (id, name)
2 AS (SELECT 1, 'siva' FROM DUAL
3 UNION ALL
4 SELECT 2, 'raja' FROM DUAL
5 UNION ALL
6 SELECT 3, 'python' FROM DUAL
7 UNION ALL
8 SELECT 4, 'sql' FROM DUAL
9 UNION ALL
10 SELECT 5, 'odi' FROM DUAL),
11 temp AS (SELECT id, name, ROW_NUMBER () OVER (ORDER BY id) rn FROM test)
12 SELECT b.name
13 FROM temp a JOIN temp b ON b.rn = a.rn + 3
14 WHERE a.name = '&name';
Enter value for name: siva
NAME
------
sql
SQL> /
Enter value for name: raja
NAME
------
odi
SQL> /
Enter value for name: sql
no rows selected
SQL>
You can simply use sub-query :
SELECT Next_NAME
FROM (SELECT NAME, LEAD(NAME, 3) OVER (ORDER by id) AS Next_NAME
FROM TEST_TABLE
) t
WHERE NAME = 'SIVA';
I am trying to write a Query to show Id, Name and No. of department in given Table which are referring more than one department.
ID Name Department
-- ---- ----------
1 Sam HR
1 Sam FINANCE
2 Ron PAYROLL
3 Kia HR
3 Kia IT
Result :
ID Name Department
-- ---- ----------
1 Sam 2
3 Kia 2
I tried using group by id and using count(*), but query is giving error.
How can I do this?
Without seeing your query, a blind guess is that you wrongly wrote the GROUP BY clause (if you used it) and forgot to include the HAVING clause.
Anyway, something like this might be what you're looking for:
SQL> with test (id, name, department) as
2 (select 1, 'sam', 'hr' from dual union
3 select 1, 'sam', 'finance' from dual union
4 select 2, 'ron', 'payroll' from dual union
5 select 3, 'kia', 'hr' from dual union
6 select 3, 'kia', 'it' from dual
7 )
8 select id, name, count(*)
9 from test
10 group by id, name
11 having count(*) > 1
12 order by id;
ID NAM COUNT(*)
---------- --- ----------
1 sam 2
3 kia 2
SQL>
You were right about using count(). You need to group by other columns though and only count unique departments then filter on the number in having clause.
select id, name, count(distinct department) as no_of_department
from table
group by id, name
having count(distinct department) > 1
This can also be done using analytic functions like below:
select *
from (
select id, name, count(distinct department) over (partition by id, name) as no_of_department
from table
) t
where no_of_department > 1
You can use window function with subquery :
select distinct id, name, Noofdepartment
from (select t.*, count(*) over (partition by id,name) Noofdepartment
from table t
) t
where Noofdepartment > 1;
However, you can also use group by clause:
select id, name, count(*) as Noofdepartment
from table t
group by id, name
having count(*) > 1;
For example my table contains the following data:
ID price
-------------
1 10
1 10
1 20
2 20
2 20
3 30
3 30
4 5
4 5
4 15
So given the example above,
ID price
-------------
1 30
2 20
3 30
4 20
-----------
ID 100
How to write query in oracle? first sum(distinct price) group by id then sum(all price).
I would be very careful with a data structure like this. First, check that all ids have exactly one price:
select id
from table t
group by id
having count(distinct price) > 1;
I think the safest method is to extract a particular price for each id (say the maximum) and then do the aggregation:
select sum(price)
from (select id, max(price) as price
from table t
group by id
) t;
Then, go fix your data so you don't have a repeated additive dimension. There should be a table with one row per id and price (or perhaps with duplicates but controlled by effective and end dates).
The data is messed up; you should not assume that the price is the same on all rows for a given id. You need to check that every time you use the fields, until you fix the data.
first sum(distinct price) group by id then sum(all price)
Looking at your desired output, it seems you also need the final sum(similar to ROLLUP), however, ROLLUP won't directly work in your case.
If you want to format your output in exactly the way you have posted your desired output, i.e. with a header for the last row of total sum, then you could set the PAGESIZE in SQL*Plus.
Using UNION ALL
For example,
SQL> set pagesize 7
SQL> WITH DATA AS(
2 SELECT ID, SUM(DISTINCT price) AS price
3 FROM t
4 GROUP BY id
5 )
6 SELECT to_char(ID) id, price FROM DATA
7 UNION ALL
8 SELECT 'ID' id, sum(price) FROM DATA
9 ORDER BY ID
10 /
ID PRICE
--- ----------
1 30
2 20
3 30
4 20
ID PRICE
--- ----------
ID 100
SQL>
So, you have an additional row in the end with the total SUM of price.
Using ROLLUP
Alternatively, you could use ROLLUP to get the total sum as follows:
SQL> set pagesize 7
SQL> WITH DATA AS
2 ( SELECT ID, SUM(DISTINCT price) AS price FROM t GROUP BY id
3 )
4 SELECT ID, SUM(price) price
5 FROM DATA
6 GROUP BY ROLLUP(id);
ID PRICE
---------- ----------
1 30
2 20
3 30
4 20
ID PRICE
---------- ----------
100
SQL>
First do the DISTINCT and then a ROLLUP
SELECT ID, SUM(price) -- sum of the distinct prices
FROM
(
SELECT DISTINCT ID, price -- distinct prices per ID
FROM tab
) dt
GROUP BY ROLLUP(ID) -- two levels of aggregation, per ID and total sum
SELECT ID,SUM(price) as price
FROM
(SELECT ID,price
FROM TableName
GROUP BY ID,price) as T
GROUP BY ID
Explanation:
The inner query will select different prices for each ids.
i.e.,
ID price
-------------
1 10
1 20
2 20
3 30
4 5
4 15
Then the outer query will select SUM of those prices for each id.
Final Result :
ID price
----------
1 30
2 20
3 30
4 20
Result in SQL Fiddle.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE MYTABLE ( ID, price ) AS
SELECT 1, 10 FROM DUAL
UNION ALL SELECT 1, 10 FROM DUAL
UNION ALL SELECT 1, 20 FROM DUAL
UNION ALL SELECT 2, 20 FROM DUAL
UNION ALL SELECT 2, 20 FROM DUAL
UNION ALL SELECT 3, 30 FROM DUAL
UNION ALL SELECT 3, 30 FROM DUAL
UNION ALL SELECT 4, 5 FROM DUAL
UNION ALL SELECT 4, 5 FROM DUAL
UNION ALL SELECT 4, 15 FROM DUAL;
Query 1:
SELECT COALESCE( TO_CHAR(ID), 'ID' ) AS ID,
SUM( PRICE ) AS PRICE
FROM ( SELECT DISTINCT ID, PRICE FROM MYTABLE )
GROUP BY ROLLUP ( ID )
ORDER BY ID
Results:
| ID | PRICE |
|----|-------|
| 1 | 30 |
| 2 | 20 |
| 3 | 30 |
| 4 | 20 |
| ID | 100 |
Say I have a table like the following (I'm on Oracle 10g btw)
NAME VALUE
------ ------
BOB 1
BOB 2
BOB 4
SUZY 1
SUZY 2
SUZY 3
How can I select all rows where value is closest to, but not greater than, a given number. For example if I want to find all the rows where value is closest to 3 I would get:
NAME VALUE
------ ------
BOB 2
SUZY 3
This seems like it should be simple... but I'm having no luck.
Thanks!
SELECT name, max(value)
FROM tbl
WHERE value <= 3
GROUP BY name
This works (SQLFiddle demo):
SELECT name, max(value)
FROM mytable
WHERE value <= 3
GROUP BY name
Based on hagensofts answer:
SELECT name, max(value)
FROM tbl
WHERE value <= 3 AND ROWNUM <=2
GROUP BY name
With ROWNUM you can limit the output rows, so if you want 2 row, then you can limit the rownum.
WITH v AS (
SELECT 'BOB' NAME, 1 value FROM dual
UNION ALL
SELECT 'BOB', 2 FROM dual
UNION ALL
SELECT 'BOB', 4 FROM dual
UNION ALL
SELECT 'SUZY', 1 FROM dual
UNION ALL
SELECT 'SUZY', 2 FROM dual
UNION ALL
SELECT 'SUZY', 3 FROM dual
)
SELECT *
FROM v
WHERE (name, value) IN (SELECT name, MAX(value)
FROM v
WHERE value <= :num
GROUP BY name)
;
I am trying to get the percentage of rows that a set of particular value has. Best explained by example. I can do this by each column very simply using ratio-to-report function and over(), but am having issues with multiple groupings
Assume table has 2 columns:
column a column b
1000 some data
1100 some data
2000 some data
1400 some data
1500 some data
With the following query, I can get for this domain set, each one is 20% of the total rows
select columna, count(*), trunc(ratio_to_report(count(columna)) over() * 100, 2) as perc
from table
group by columna
order by perc desc;
However, what I need is for example to determine the percentage & count of the rows that contain 1000, 1400 or 2000; From looking at it, you can tell its 60%, but need a query to return that. This needs to be efficient, as the query will be running against millions of rows. Like I said before, I have this working on a single value and its percentage, but the multiple is what is throwing me.
Seems like I need to be able to put an IN clause somewhere, but the values will not be these specific values each time. I will need to get the values for the "IN" part of it from another table, if that makes sense. guess I need some kind of multiple grouping.
Potentially, you're looking for something like
SQL> ed
Wrote file afiedt.buf
1 with x as (
2 select 1000 a from dual
3 union all
4 select 1100 from dual
5 union all
6 select 1400 from dual
7 union all
8 select 1500 from dual
9 union all
10 select 2000 from dual
11 )
12 select (case when a in (1000,1400,1500)
13 then 1
14 else 0
15 end) bucket,
16 count(*),
17 ratio_to_report(count(*)) over ()
18 from x
19 group by (case when a in (1000,1400,1500)
20 then 1
21 else 0
22* end)
SQL> /
BUCKET COUNT(*) RATIO_TO_REPORT(COUNT(*))OVER()
---------- ---------- -------------------------------
1 3 .6
0 2 .4
I'm not sure I entirely understand the requirement, but do you need ratio_to_report at all? Have a look at the following, and let me know how close this is to what you want, and we can work from there!
T1 is the table containing your sample data
create table t1(a primary key) as
select 1000 as a from dual union all
select 1100 as a from dual union all
select 1400 as a from dual union all
select 1500 as a from dual union all
select 2000 as a from dual;
T2 is the lookup table you mentioned (where you get the list of IDs)
create table t2(a primary key) as
select 1000 as a from dual union all
select 1400 as a from dual union all
select 2000 as a from dual;
A left join from T1->T2 will return all rows in T1 paired with all matching rows in T2. For each A in T1 that does not exist in your set (T2), the result will be padded with NULL. We can exploit the fact that COUNT() doesn't count (hehe) nulls.
select count(t1.a) as num_rows
,count(t2.a) as in_set
,count(t2.a) / count(t1.a) as shr_in_set
from t1
left
join t2 on(t1.a = t2.a);
The result of running the query is:
NUM_ROWS IN_SET SHR_IN_SET
---------- ---------- ----------
5 3 ,6