single row multiple columns into one column using sql server - sql

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

Related

How to concatenate consecutive rows in oracle

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

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.

SQL Server query - get items that exist in more than one column

I have a simple table which contains barcode ids of tools and associated room location in which the tool should belong to.
Unfortunately, I've noticed that some users have entered the same barcode id for another room location.
For example, I have these 2 columns:
barcodeNumber | RoomLocation
--------------+-------------
123456 | 400
654321 | 300
875421 | 200
654321 | 400
999999 | 250
878787 | 300
777777 | 400
999999 | 200
Note that barcodeNumber "654321" is stored in roomLocations 300 & 400 ad "999999" are stored in room locations 200 & 250
How do I write the SQL query to list the duplicate barcode Number and RoomLocation they are located in and not just the "count" of duplicates?
For example, the end result I wish to see is:
654321 | 300
654321 | 400
999999 | 200
999999 | 250
Using window functions (SQL:1999) you would get the result like this:
with c as (
select barcodeNumber, RoomLocation,
count(*) over(partition by barcodeNumber) cnt
from t)
select barcodeNumber, RoomLocation
from c where cnt > 1
order by 1,2
You can also use SQL-92 syntax:
select barcodeNumber, RoomLocation
from t
where barcodeNumber IN (
select barcodeNumber from t
group by barcodeNumber
having count(*) > 1)
order by 1,2
You can try this also. Use count(*) over (partition by barcodenumber) to determine the duplicate values.
create table #sample (barcodenumber nvarchar(30),roomlocation int)
insert into #sample (barcodenumber,roomlocation)
select '123456',400 union all
select '654321',300 union all
select '875421',200 union all
select '654321',400 union all
select '999999',250 union all
select '878787',300 union all
select '777777',400 union all
select '999999',200
select barcodenumber,roomlocation from (
select *, count(*) over (partition by barcodenumber) as rnk
from #sample
)t
group by barcodenumber,roomlocation,rnk
having rnk >1
Hope this could help.
Do you want to find the duplicate barcode?
;WITH tb(barcodenumber,roomlocation)AS(
SELECT '123456',400 UNION ALL
SELECT '654321',300 UNION ALL
SELECT '875421',200 UNION ALL
SELECT '654321',400 UNION ALL
SELECT '999999',250 UNION ALL
SELECT '878787',300 UNION ALL
SELECT '777777',400 UNION ALL
SELECT '999999',200
)
SELECT * FROM (
SELECT *,COUNT(0)OVER(PARTITION BY tb.barcodenumber) AS cnt FROM tb
) AS t WHERE t.cnt>1
barcodenumber roomlocation cnt
------------- ------------ -----------
654321 400 2
654321 300 2
999999 200 2
999999 250 2
Here is another way to achive your result:
SELECT barcodenumber, roomlocation
FROM table_name
WHERE barcodenumber IN (
SELECT barcodenumber
FROM table_name
GROUP BY barcodenumber
HAVING COUNT(DISTINCT roomlocation) > 1);
--If you dont have duplicate rows then just use COUNT(*)
Use JOIN and HAVING clause :
SELECT A.barcodenumber,roomlocation
FROM #sample
JOIN
(
SELECT barcodenumber
FROM #sample
GROUP BY barcodenumber
HAVING COUNT(*) > 1
) A ON A.barcodenumber = #sample.barcodenumber

Oracle sql group sum

I have table With ID,Sub_ID and value coloumns
ID SUB_ID Value
100 1 100
100 2 150
101 1 100
101 2 150
101 3 200
102 1 100
SUB ID can vary from 1..maxvalue( In this example it is 3). I need Sum of values for each Sub_ID. If SUB_ID is less than MAXVALUE for a particlaur ID then it should take MAX(SUB_ID) of each ID As shown below ( In this example for ID=100 for SUB_ID 3 it should take 150 i.e 2<3 so value=150))
SUB_ID SUM(values) Remarks
1 300 (100+100+100)
2 400 (150+150+100)
3 450 (150+200+100)
This can be easily done in PL/SQL . Can we use SQL for the same using Model Clause or any other options
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TableA ( ID, SUB_ID, Value ) AS
SELECT 100, 1, 100 FROM DUAL
UNION ALL SELECT 100, 2, 150 FROM DUAL
UNION ALL SELECT 101, 1, 100 FROM DUAL
UNION ALL SELECT 101, 2, 150 FROM DUAL
UNION ALL SELECT 101, 3, 200 FROM DUAL
UNION ALL SELECT 102, 1, 100 FROM DUAL
Query 1:
WITH sub_ids AS (
SELECT LEVEL AS sub_id
FROM DUAL
CONNECT BY LEVEL <= ( SELECT MAX( SUB_ID ) FROM TableA )
),
max_values AS (
SELECT ID,
MAX( VALUE ) AS max_value
FROM TableA
GROUP BY ID
)
SELECT s.SUB_ID,
SUM( COALESCE( a.VALUE, m.max_value ) ) AS total_value
FROM sub_ids s
CROSS JOIN
max_values m
LEFT OUTER JOIN
TableA a
ON ( s.SUB_ID = a.SUB_ID AND m.ID = a.ID )
GROUP BY
s.SUB_ID
Results:
| SUB_ID | TOTAL_VALUE |
|--------|-------------|
| 1 | 300 |
| 2 | 400 |
| 3 | 450 |
Try this
SELECT SUB_ID,SUM(values),
(SELECT DISTINCT SUBSTRING(
(
SELECT '+'+ CAST(values AS VARCHAR)
FROM table_Name AS T2
WHERE T2.SUB_ID = d.SUB_ID
FOR XML PATH ('')
),2,100000)[values]) as values
FROm table_Name d
GROUP BY SUB_ID
How about something like this:
select max_vals.sub_id, sum(nvl(table_vals.value,max_vals.max_value)) as sum_values
from (
select all_subs.sub_id, t1.id, max(t1.value) as max_value
from your_table t1
cross join (select sub_id from your_table) all_subs
group by all_subs.sub_id, t1.id
) max_vals
left outer join your_table table_vals
on max_vals.id = table_vals.id
and max_vals.sub_id = table_vals.sub_id
group by max_vals.sub_id;
The inner query gets you a list of all sub_id/id combinations and their fall-back values. The out query uses an nvl to use the table value if it exists and the fall-back value if it doesn't.

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;