SQL select combine data from multiple rows into a single row - sql

I have a table that looks similar to this:
ID OLD NEW TIME
1 a b 5
1 b c 7
1 c d 45
1 d e 4
2 a b 1
2 b d 8
2 d e 45
3 b c 15
3 c d 14
And I would like to build a report that looks like this (basically for each OLD data point grab the TIME value):
ID TimeForA TimeForB TimeForC TimeForD
1 5 7 45 4
2 1 8 NULL 45
3 NULL 15 14 NULL
I have been able to get all the data into the correct columns, but have not been able to combine each row into a single row for each ID. My current query looks like this (no I don't have every column in place yet, still just testing):
WITH CTE (id, ATime, BTime)
AS
(
select T1.oid, T1.loggedFor, null, T1.time as Atime
from Table1 T1
where T1.OLD = 'a'
union
select T1.oid, T1.loggedFor, T1.time as BTime, null
from Table1 T1
where T1.old = 'b'
)
select ID, ATime, BTime
from CTE
order by ID
Any help appreciated!

Try this:
select id,
sum(if(old = 'a',time,null)) as time_for_a,
sum(if(old = 'b',time,null)) as time_for_b,
sum(if(old = 'c',time,null)) as time_for_c,
sum(if(old = 'd',time,null)) as time_for_d
from test_tbl
group by id
order by id;

Related

How to update table with concatenation

I have table like this
create table aaa (id int not null, data varchar(50), numb int);
with data like this
begin
for i in 1..30 loop
insert into aaa
values (i, dbms_random.string('L',1),dbms_random.value(0,10));
end loop;
end;
now im making this
select a.id, a.data, a.numb,
count(*) over (partition by a.numb order by a.data) count,
b.id, b.data,b.numb
from aaa a, aaa b
where a.numb=b.numb
and a.data!=b.data
order by a.data;
and i want to update every row where those numbers are the same but with different letters, and in result i want to have new data with more than one letter (for example in data column- "a c d e"), i just want to create concatenation within. How can i make that? the point is to make something like group by for number but for that grouped column i would like to put additional value.
that is how it looks like in begining
id | data |numb
1 q 1
2 z 8
3 i 7
4 a 2
5 q 4
6 h 1
7 b 9
8 u 9
9 s 4
That i would like to get at end
id | data |numb
1 q h 1
2 z 8
3 i 7
4 a 2
5 q s 4
7 b u 9
Try this
SELECT MIN(id),
LISTAGG(data,' ') WITHIN GROUP(
ORDER BY data
) data,
numb
FROM aaa GROUP BY numb
ORDER BY 1
Demo
This selects 10 random strings 1 to 4 letters long, letters in words may repeat:
select level, dbms_random.string('l', dbms_random.value(1, 4))
from dual connect by level <= 10
This selects 1 to 10 random strings 1 to 26 letters long, letters do not repeat and are sorted:
with aaa(id, data, numb) as (
select level, dbms_random.string('L', 1),
round(dbms_random.value(0, 10))
from dual connect by level <= 30)
select numb, listagg(data) within group (order by data) list
from (select distinct data, numb from aaa)
group by numb

How to select a value with a column name that also needs selected?

The SQL Server 2005 table I'm working from is really strange. Here's a simplified example:
TABLE 1:
key | a | b | c | d | e | f
z 0 1 2 3 4 5 6
y 1 8 9 10 11 12 13
x 14 15 16 17 18 19 20
w 21 22 23 24 25 26 27
TABLE 2:
id | Value
1 a
2 b
3 c
4 e
5 f
What I need to accomplish is to, in a single statement, select the column name from a different table, then get the value here. So it would be something like "Select (select colName from table2 where id=VAR1) From table1 where key = VAR2"
So table2 will return either a/b/c/d/e/f, and then the main statement will get the value of the corresponding value based on the key.
Table2 will always return a-f, and I will know the VAR1 and VAR2 ahead of time.
You can use UNPIVOT:
SELECT [key], val, col
FROM
(SELECT [key], a, b, c, d, e, f
FROM table1
WHERE [key] = #var2) AS src
UNPIVOT
(val FOR col IN
(a, b, c, d, e, f)
)AS unpvt
WHERE col = (SELECT value FROM table2 WHERE id = #var1)
UNPIVOT operation transposes table data from columns to rows creating an extra field where column name is placed. This way you can query table data using the name of the column that is obtained from table2.
Demo here

SQL Inner Join and Partitioning To obtain RowNumbers when matching

I have 2 tables. The first table 'a' the second 'b'.
I am writing a query that grabs every row in table a (there is 33 rows defined) and inner joins table b where the EnclLocation or the BackPanLoc match the Workcell in table A.
I only want a row from table B where they match based off BackPan and EnclLocation but they are not the same records. table b has a few rows of data that is assigned to the same workcell as table a. I am just trying to retrieve those additional rows and partition it.
I attached table a and table b. I also attached the desired results for this query with respect to Workcell 10 only as an example... As you can see, table B has 4 records that has either the EnclLocation or the BackPanLoc = 10. But my results only show the same DelvNumber 4 times. any help is most appreicated.
Table a
Table b
Incorrect Results
Desired Results (showing only Workcell 10 as an example)
workcell DelvNumber RowNum
1 447910-02 1
2 445710-01 1
2 445710-01 2
3 444291-01 1
3 444291-01 2
4 447910-03 1
4 447910-03 2
5 648020-01 1
6 647800-02 1
7 646920-01 1
7 646920-01 2
8 644830-4-8 1
8 644830-4-8 2
9 443990-01 1
10 645960-01-03 1
10 445710-11 2
10 445710-02 3
10 445710-09 4
Code Used
WITH ss
AS (SELECT a.*,
Row_number()
OVER(
partition BY a.workcell
ORDER BY a.workcell) AS rownum
FROM nwcurrent a
INNER JOIN nwdeliverables b
ON b.encllocation = a.workcell
OR b.backpanloc = a.workcell
WHERE ( b.status < 9
AND ( b.encllocation <> 0
OR b.backpanloc <> 0 )
OR a.delvnumber = '123' ))
SELECT *
FROM ss
copy and paste format
1 447910-02 1
2 445710-01 1
2 445710-01 2
3 444291-01 1
3 444291-01 2
4 447910-03 1
4 447910-03 2
5 648020-01 1
6 647800-02 1
7 646920-01 1
7 646920-01 2
8 644830-4-8 1
8 644830-4-8 2
9 443990-01 1
10 645960-01-03 1
10 445710-11 2
10 445710-02 3
10 445710-09 4
SQLFiddle
http://sqlfiddle.com/#!3/a8682/4
A new try...
SELECT a.workcell
,a.DelvNumber AS A_DelvNumber
,b.DelvNumber AS B_DelvNumber
,CASE WHEN a.DelvNumber<>b.DelvNumber THEN b.DelvNumber ELSE a.DelvNumber END AS DelvNumber_Resolved
,Row_number() OVER(partition BY a.workcell ORDER BY a.workcell) AS rownum
FROM NWCurrent a
INNER JOIN NWDeliverables AS b ON b.EnclLocation=a.WorkCell OR b.BackPanLoc=a.WorkCell
WHERE (b.status <9 AND (b.EnclLocation<>0 OR b.BackPanLoc<>0)OR a.DelvNumber='123')

how to Get only the rows which's D column hold nearest lowest number to the C column?

------------------------------------------
ID Name C D
------------------------------------------
1 AK-47 10 5
2 RPG 10 20
3 Mp5 20 15
4 Sniper 20 18
5 Tank 90 80
6 Space12 90 20
7 Rifle 90 110
8 Knife 90 85
Consider 1,2 ; 3,4 ; 5,6,7,8 are as separate groups
So i need to get the row group wise that which's D column holds the nearest lower number to the C column
So the Expected Result is :
------------------------------------------
ID Name C D
------------------------------------------
1 AK-47 10 5
4 Sniper 20 18
8 Knife 90 85
How can I achieve this ?
select t1.*
from your_table t1
join
(
select c, min(abs(c-d)) as near
from your_table
group by c
) t2 on t1.c = t2.c and abs(t1.c-t1.d) = t2.near
Here is the syntax for another way of doing this. This uses a cte and will only hit the base table once.
with MySortedData as
(
select ID, Name, C, D, ROW_NUMBER() over(PARTITION BY C order by ABS(C - D)) as RowNum
from Something
)
select *
from MySortedData
where RowNum = 1

Copying existing rows in a table

How do I go about doing the following?
I am using the following query to get a specific users tab ids:
select id
from intranet.dbo.tabs
where cms_initials = #user
order by id asc
which might return the following ids
4
5
6
7
I now want to insert the rows from the following query:
select tabs_id, widgets_id, sort_column, sort_row
from intranet.dbo.columns c
inner join intranet.dbo.tabs t on c.tabs_id = t.id
where t.is_default = 1
But use the ids from the first query to replace the tab ids
so if the second query originally returns tabs_id's as
0
0
0
0
1
1
1
2
2
2
3
3
I should end up with
0
0
0
0
1
1
1
2
2
2
3
3
4
4
4
4
5
5
5
6
6
6
7
7
Is this possible with sql server 2005 without using stored procedures?
So far I have
insert into intranet.dbo.columns ( tabs_id, widgets_id, sort_column, sort_row )
select tabs_id, widgets_id, sort_column, sort_row
from intranet.dbo.columns c
inner join intranet.dbo.tabs t on c.tabs_id = t.id
where t.is_default = 1
But this just copies everything as is, I need to do that, but replace the ids in the copied rows.
This solution uses common table expressions and ranking functions. A and B are your original queries ranked by tab order. A and B are then joined by tab ranking and inserted.
USE intranet
;WITH A AS
(
SELECT ROW_NUMBER() OVER (ORDER BY id) AS tab_ranking
, id
FROM dbo.tabs
WHERE cms_initials = #user
),
B AS
(
SELECT DENSE_RANK() OVER (ORDER BY tabs_id) AS tab_sequence
, tabs_id, widgets_id, sort_column, sort_row
FROM dbo.columns
WHERE tabs_id IN (SELECT t.id FROM dbo.tabs t WHERE t.is_default = 1)
)
INSERT INTO dbo.columns (tabs_id, widgets_id, sort_column, sort_row)
SELECT a.id, b.widgets_id, b.sort_column, b.sort_row
FROM A
INNER JOIN B ON B.tab_ranking = A.tab_ranking