How to concatenate consecutive rows in oracle - sql

am beginner to oracle. I tried following source code to solve and get as following O/P.But cant, please give some ideas to solve this.
id product sales
--- ------------- --------
1 Soaps 1200
2 Ice cream 2300
3 Cool drinks 2500
4 Tv 5000
5 Mobile 10000
6 Washing machine 20000```
```O/P
id product sales
--- ------------- --------
1 Soaps 1200
2 Ice cream+Cool drinks 4800
3 Tv+Mobile 15000
6 Washing machine 20000```

There must be a category and product mapping table.
Product with category must be mapped to resolve your issue.
Select min(t.id) as id,
Listagg(t.product, ' + ') within group (order by t.id) as product,
Sum(t.sales) as sales
From your_table t
Join mapping_table m
On (m.product = t.product)
Group by m.catrgory;
Cheers!!

You can use lead() analytic function :
with t1 as
(
select id,
concat(concat(product,'+'),lead(product) over (order by id)) as product,
sales + lead(sales) over (order by id) as sales
from tab -- your original table
), t2 as
(
select *
from t1
where id in (2,4)
union all
select *
from tab
where id in (1,6)
)
select *
from t2
order by id;
Demo

I thing, You need add column for group by. Try please:
WITH temp as (SELECT 1 id, 1 group_id, 'Soaps' str, 1200 as price FROM dual
UNION ALL
SELECT 2 id, 2, 'Ice cream', 2300 FROM dual
UNION ALL
SELECT 3 id, 2, 'Cool drinks', 2300 FROM dual
UNION ALL
SELECT 4 id, 3, 'Tv', 5000 FROM dual
UNION ALL
SELECT 5 id, 3, 'Mobile', 10000 FROM dual
UNION ALL
SELECT 6 id, 4, 'Washing machine', 20000 FROM dual)
SELECT group_id, LISTAGG(str, ', ')
WITHIN GROUP (ORDER BY group_id) "str",
sum(price) price
FROM temp
GROUP BY group_id
result:
1 Soaps 1200
2 Cool drinks, Ice cream 4600
3 Mobile, Tv 15000
4 Washing machine 20000

Related

how to get first word repetitive at front then rest word in listagg?

I am not sure how to get the right script
usually, I use listagg by order by but I want something different
select
customer_id ,
listagg (car_product , '-' ) within group (order by car_product) as Product
from purchase
group by
customer_id
I want output results like keep first ZINC then the rest are listagg, here is an example;
customer_id
product
123
ZINC-BLUE-RED
939
BLACK-BLUE
567
ZINC-BLACK-RED-YELLOW
yep 939 - doesn't have ZINC so just pick other in there
thank you
Fix order by clause so that it sorts ZINC first, and then the rest.
Sample data:
SQL> with purchase (customer_id, car_product) as
2 (select 123, 'ZINC' from dual union all
3 select 123, 'BLUE' from dual union all
4 select 123, 'RED' from dual union all
5 --
6 select 939, 'BLACK' from dual union all
7 select 939, 'BLUE' from dual
8 )
Query:
9 select customer_id,
10 listagg(car_product, '-') within group
11 (order by case when car_product = 'ZINC' then 'A' else car_product end) as product
12 from purchase
13 group by customer_id;
CUSTOMER_ID PRODUCT
----------- --------------------
123 ZINC-BLUE-RED
939 BLACK-BLUE
SQL>

Oracle SQL - Group by a column and extract other values to columns

My idea is to do something like this:
INPUT:
ID CURRENCY AMOUNT
1 RUS 14,55
1 USD 22,22
1 PLN 444,44
2 PLN 22
Then I want to group by ID and get output:
ID CUR_1 AMOUNT_1 CUR_2 AMOUNT_2 CUR_3 AMOUNT_3
1 RUS 14,55 USD 22,22 PLN 444,44
2 PLN 22
It is important to combine the right amount with right currency. Maximal number of pairs is 3 like for an ID=1. It may vary from 1 to 3.
I tried using LISTAGG but it will generate problem with further processing of the data.
select *
from (select t.*, row_number() over (partition by id order by null) rn
from t)
pivot (max(currency) cur, sum(amount) amt for rn in (1, 2, 3))
Test:
with t(id, currency, amount) as (
select 1, 'RUS', 14.55 from dual union all
select 1, 'USD', 22.22 from dual union all
select 1, 'PLN', 444.44 from dual union all
select 2, 'PLN', 22 from dual )
select *
from (select t.*, row_number() over (partition by id order by null) rn
from t)
pivot (max(currency) cur, sum(amount) amt for rn in (1, 2, 3))
Output:
ID 1_CUR 1_AMT 2_CUR 2_AMT 3_CUR 3_AMT
---------- ----- ---------- ----- ---------- ----- ----------
1 RUS 14,55 USD 22,22 PLN 444,44
2 PLN 22
You can create a virtual table for each row using a subquery, then join the virtual tables by ID into a single row.

Select Duplicate records in Oracle

I have a table below in Oracle
Table1
State | Product |other fields
CA | P1 | xxxx
OR | P1 | xxxx
OR | P1 | xxxx
OR | P1 | xxxx
WA | P1 | xxxx
VA | P2 | xxxx
My Output should be only select if State has been occurred more than once.
State | Product |other fields
OR | P1 | xxxx
If you just want to count duplicate states then:
SELECT DISTINCT
State,
Product,
Other_Fields
FROM (
SELECT t.*,
COUNT(1) OVER ( PARTITION BY State ) AS cnt
FROM Table1 t
)
WHERE cnt > 1;
If you want to consider duplicate rows (considering all fields) then:
SELECT *
FROM Table1
GROUP BY State, Product, Other_Fields
HAVING COUNT(1) > 1;
select state, product, column_3, column_4
from (
select state, product, column_3, column_4,
count(*) over (partition by state) as cnt
from the_table
) t
where cnt > 1;
You could use ROW_NUMBER analytic function.
For example,
SQL> WITH sample_data AS(
2 SELECT 'CA' State, 'P1' product FROM dual UNION ALL
3 SELECT 'OR', 'P1' product from dual union all
4 SELECT 'OR', 'P1' product FROM dual UNION ALL
5 SELECT 'OR', 'P1' product FROM dual UNION ALL
6 SELECT 'WA', 'P1' product FROM dual UNION ALL
7 SELECT 'VA', 'P2' product from dual
8 )
9 -- end of sample_data mimicking real table
10 SELECT distinct state,
11 product
12 FROM
13 (SELECT state,
14 product,
15 row_number() OVER(PARTITION BY state ORDER BY product) rn
16 FROM sample_data
17 )
18 WHERE rn >1;
ST PR
-- --
OR P1
SQL>

Oracle SQL - order table

I am new to Oracle SQL and have a table below.
TABLE NAME : ORDERS
CNUM AMT SNUM
1001 1000 2001
1002 2000 2002
1001 1500 2001
1001 500 2001
need to get only those data where cnum (customer number) is serviced by more than 3 snum(sales person) from this above table
thank you
Asit
Something like that?
select cnum, count(*), sum(amount)
from orders
group by cnum
having count(*) > 3
Not sure what you need - aggregate result or every single row. If you need every row then try this one:
select * from (
select a.*, count(*) over(partition by cnum) cnt
from orders a
)
where cnt > 3
You could use the analytic function ROW_NUMBER.
For example,
SQL> WITH DATA AS(
2 SELECT t.*, row_number() OVER(PARTITION BY cnum ORDER BY snum) rn FROM t
3 )
4 SELECT cnum, amt, snum FROM DATA
5 WHERE rn >=3;
CNUM AMT SNUM
---------- ---------- ----------
1001 1500 2001
SQL>
Based on your sample data, the above gives the result including 3 snum for cnum, if you want more than 3, then replace >= with >.
You can group and count distinct SNUMs:
select CNUM
from ORDERS
group by CNUM
having count(distinct SNUM) > 3
WITH tab
AS (SELECT 1001 CNUM, 1000 AMT, 2001 SNUM FROM DUAL
UNION ALL
SELECT 1002, 2000, 2002 FROM DUAL
UNION ALL
SELECT 1001, 1500, 2001 FROM DUAL
UNION ALL
SELECT 1001, 500, 2001 FROM DUAL)
SELECT cnum
FROM tab
GROUP BY cnum
HAVING COUNT (*) >= 3;
If you only need the cnum and the snum you could do the following witch is partially taken from Rusty's answer:
WITH tab
AS (SELECT 1001 CNUM, 1000 AMT, 2001 SNUM FROM DUAL
UNION ALL
SELECT 1002, 2000, 2002 FROM DUAL
UNION ALL
SELECT 1001, 1500, 2001 FROM DUAL
UNION ALL
SELECT 1001, 500, 2001 FROM DUAL)
SELECT DISTINCT cnum, snum
FROM (SELECT cnum, snum, COUNT (*) OVER (PARTITION BY cnum) RANK FROM tab)
WHERE RANK >= 3;

single row multiple columns into one column using sql server

I have table like this
OrderNo Item_Description1 Rate1 Quantity1 Item_Description2 Rate2 Quantity2 Item_Description3 Rate3 Quantity3
-------- ------------------ ------ ---------- ------------------ ------ ---------- ------------------ ------ ----------
1001 Laptop 50000 8 Air Conditioner 20000 10 Television 25000 12
1002 Washing Machine 35000 10 Camera 4000 20 Speaker 1500 15
From this I need to create a temp table or table like this:
OrderNo Item_Description Rate Quantity
-------- ------------------ ------ ----------
1001 Laptop 50000 8
Air Conditioner 20000 10
Television 25000 12
1002 Washing Machine 35000 10
Camera 4000 20
Speaker 1500 15
Is there a way I can do this in SQL Server?
You can also use CROSS APPLY to unpivot the data:
select t.order_no,
c.item_description,
c.rate,
c.quantity
from yourtable t
cross apply
(
select item_description1, rate1, quantity1 union all
select item_description2, rate2, quantity2 union all
select item_description3, rate3, quantity3
) c (item_description, rate, quantity)
SELECT * FROM
(select ORDER_NO,ITEM_DESCRIPTION1,RATE1,QUANTITY1FROM TABLE
UNION
select ORDER_NO,ITEM_DESCRIPTION2,RATE2,QUANTITY2 FROM TABLE
UNION
select ORDER_NO,ITEM_DESCRIPTION3,RATE3,QUANTITY3 FROM TABLE)AS A ORDER BY ORDER_NO
Try this
SELECT t.*
FROM Table1
OUTER APPLY
(
VALUES
([OrderNo],item_description1, rate1, quantity1),
(NULL, item_description2, rate2, quantity2),
(NULL, item_description3, rate3, quantity3)
) t([OrdNo],item_description, rate, quantity)
SQL FIDDLE DEMO
Or use #bluefeet answer with NULL
SELECT c.[OrderNo],
c.item_description,
c.rate,
c.quantity
FROM Table1 t
CROSS APPLY
(
SELECT [OrderNo],item_description1, rate1, quantity1 UNION ALL
SELECT NULL, item_description2, rate2, quantity2 UNION ALL
SELECT NULL, item_description3, rate3, quantity3
) c ([OrderNo],item_description, rate, quantity)
SQL FIDDLE DEMO
hope to help you!
select t.* from
(
select order_No, Item_Description1 as Item_Desription, Rate1 as Rate
from Table
union
select order_No, Item_Description2 as Item_Desription, Rate2 as Rate
from Table
union
select order_No, Item_Description3 as Item_Desription, Rate3 as Rate
from Table
) as t
Order by t.order_No asc
this is my test
select t.* from
(select id, apple1 as apple, orange1 as orange
from Test
union all
select id, apple2 as apple, orange2 as orange
from Test
union all
select id, apple3 as apple, orange3 as orange
from Test) as t
order by t.id asc