Is there a way to join row values from 3 to 3? - sql

As I mentioned in the title, I need to get values from the first 3 rows, then the second 3 rows, and on, and join them in rows.
Example
Input:
column
-------
Mu1
Mu2
Mu3
Mu4
Mu5
Mu6
Mu7
Mu8
Mu9
Output:
Column
------------
Mu1,Mu2,Mu3
Mu4,Mu5,Mu6
Mu7,Mu8,Mu9
Thank you so much, and I'm sorry if I'm posting something in the wrong way, this is my first question here.

You can use a window function (row_number) inside a CTE to assign a row number to each of your row.
Then you can use a group by with string_agg to concatenate your values 3 rows at a time:
declare #t table (col varchar(5))
insert into #t
values
('Mu1'),
('Mu2'),
('Mu3'),
('Mu4'),
('Mu5'),
('Mu6'),
('Mu7'),
('Mu8'),
('Mu9')
;with grp as
(
select col,
rn = row_number() over (order by col)
from #t
)
select
string_agg(col, ',') as [Column]
from grp
group by (rn -1)/ 3
Results:

Related

Maintain order when using SQLite WHERE-clause and IN operator

Consider the following tbl:
CREATE TABLE tbl (ID INTEGER, ticker TEXT, desc TEXT);
INSERT INTO tbl (ID, ticker, desc)
VALUES (1, 'GDBR30', '30YR'),
(2, 'GDBR10', '10YR'),
(3, 'GDBR5', '5YR'),
(4, 'GDBR2', '2YR');
For reference, tbl looks like this:
ID ticker desc
1 GDBR30 30YR
2 GDBR10 10YR
3 GDBR5 5YR
4 GDBR2 2YR
When issuing the following statement, the result will be ordered according to ID.
SELECT * FROM tbl
WHERE ticker in ('GDBR10', 'GDBR5', 'GDBR30')
ID ticker desc
1 GDBR30 30YR
2 GDBR10 10YR
3 GDBR5 5YR
However, I need the ordering to adhere to the order of the passed list of values. Here's what I am looking for:
ID ticker desc
2 GDBR10 10YR
3 GDBR5 5YR
1 GDBR30 30YR
You can create a CTE that returns 2 columns: the values that you search for and for each value the sort order and join it to the table.
In the ORDER BY clause use the sort order column to sort the results:
WITH cte(id, ticker) AS (VALUES (1, 'GDBR10'), (2, 'GDBR5'), (3, 'GDBR30'))
SELECT t.*
FROM tbl t INNER JOIN cte c
ON c.ticker = t.ticker
ORDER BY c.id
See the demo.
The only way to be sure of the final ordering of records is to use the ORDER BY clause.
The order the list of values is given is not relevant for final ordering.
In your case your only solution is to give to each value a 'weight' to use as sort order.
You could for example change the IN operator with a INSTR function to get both a filterable and a sortable result.
Try something like that
SELECT *, INSTR(',GDBR10,GDBR5,GDBR30,', ',' || ticker || ',') POS
FROM tbl
WHERE POS>0
ORDER BY POS;
If you don't want the position in the selected fields list you can use a subquery:
SELECT *
FROM (SELECT *, INSTR(',GDBR10,GDBR5,GDBR30,', ',' || ticker || ',') pos FROM tbl) X
WHERE POS>0
ORDER BY POS;

Gow to select unique id when ids are same and have different string values in variable

I am working with Microsoft SQL Server. Now I have many same ids and the values of other variables associated with them may or may not be same.
I just want to select one unique id every time (I don't care about values of other variables). Values of other variables can be anything. I am just focused on selecting unique id and any values associated with any of the duplicate ids.
You could use the row_number function to assign a unique number to every ID, and then query just one of them:
SELECT id, variablea, variableb
FROM (SELECT id, variablea, variableb,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY varaiblea) AS rn
FROM mytable) t
WHERE rn = 1
Another option is to use the WITH TIES clause in concert with Row_Number()
Note: No Extra Field.
Example
Declare #YourTable Table ([id] int,[variableA] varchar(50),[variableB] varchar(50))
Insert Into #YourTable Values
(1,'xyz','abc')
,(1,'fgh','rty')
,(2,'qwe','ui')
,(3,'jk','vbn')
,(3,'asd','ty')
,(3,'fgh','po')
Select top 1 with ties *
From #YourTable
Order By Row_Number() over (Partition By ID Order by variableA)
Returns
id variableA variableB
1 fgh rty
2 qwe ui
3 asd ty

Postgresql : How do I select top n percent(%) entries from each group/category

We are new to postgres, we have following query by which we can select top N records from each category.
create table temp (
gp char,
val int
);
insert into temp values ('A',10);
insert into temp values ('A',8);
insert into temp values ('A',6);
insert into temp values ('A',4);
insert into temp values ('B',3);
insert into temp values ('B',2);
insert into temp values ('B',1);
select a.gp,a.val
from temp a
where a.val in (
select b.val
from temp b
where a.gp=b.gp
order by b.val desc
limit 2);
Output of above query is something like this
gp val
----------
A 10
A 8
B 3
B 2
But our requirement is different, we want to select top n% records from each category where n is not fixed, n is based of some percent of elements in each group.
To retrieve the rows based on the percentage of the number of rows in each group you can use two window functions: one to count the rows and one to give them a unique number.
select gp,
val
from (
select gp,
val,
count(*) over (partition by gp) as cnt,
row_number() over (partition by gp order by val desc) as rn
from temp
) t
where rn / cnt <= 0.75;
SQLFiddle example: http://sqlfiddle.com/#!15/94fdd/1
Btw: using char is almost always a bad idea because it is a fixed-length data type that is padded to the defined length. I hope you only did that for setting up the example and don't use it in your real table.
Referencing the response from a_horse_with_no_name, you can achieve something similar using percent_rank()
SELECT
gp,
val,
pct_rank
FROM (
SELECT
gp,
val,
percent_rank() over (order by val desc) as pct_rank
FROM variables.temp
) t
WHERE pct_rank <= 0.75;
You can then set the final WHERE clause to return data at whatever percent_rank() threshold you require.
The accepted answer did not work for me. I find this solution that works for me:
SELECT * FROM temp ORDER BY val DESC
LIMIT (SELECT (count(*) / 10) AS selnum FROM temp )
It is not optimal (performance) but it works

remove duplicate records with a criteria

I am using a script which requires only unique values. And I have a table which has duplicates like below, i need to keep only unique values (first occurrence) irrespective of what is present inside the brackets.
can I delete the records and keep the unique records using a single query?
Input table
ID Name
1 (Del)testing
2 (Del)test
3 (Delete)testing
4 (Delete)tester
5 (Del)tst
6 (Delete)tst
So the output tables should be something like
Input table
ID Name
1 (Del)testing
2 (Del)test
3 (Delete) tester
4 (Del)tst
SELECT DISTINCT * FROM FOO;
It depends how much data you have to retrieve, if you only have to change Delete -> Del you can try with REPLACE
http://technet.microsoft.com/en-us/library/ms186862.aspx
also grouping functions should help you
I don't think this would be easy query
Assumption: The name column always has all strings in the format given in the sample data.
Try this:
;with cte as
(select *, rank() over
(partition by substring(name, charindex(')',name)+1,len(name)+1 - charindex(')',name))
order by id) rn
from tbl
),
filtered_cte as
(select * from cte
where rn = 1
)
select rank() over (partition by getdate() order by id,getdate()) id , name
from filtered_cte
How this works:
The first CTE cte uses rank() to rank the occurrence of the string outside brackets in the name column.
The second CTE filtered_cte only returns the first row for each occurence of the specified string. In this step, we get the expected results, but not in the desired format.
In this step we partition by and order by the getdate() function. This function is chosen as a dummy to give us continuous values for the id column while using the rank function as we did in step 1.
Demo here.
Note that this solution will return filtered values, but not delete anything in the source table. If you wish, you can delete from the CTE created in step 1 to remove data from the source table.
First use this update to make them uniform
Update table set name = replace(Name, '(Del)' , '(Delete)')
then delete the repetitive names
Delete from table where id in
(Select id from (Select Row_Number() over(Partition by Name order by id) as rn,* from table) x
where rn > 1)
First create the input date table
CREATE TABLE test
(ID int,Name varchar(20));
INSERT INTO test
(`ID`, `Name`)
VALUES
(1, '(Del)testing'),
(2, '(Del)test'),
(3, '(Delete)testing'),
(4, '(Delete)tester'),
(5, '(Del)tst'),
(6, '(Delete)tst');
Select Query
select id, name
from (
select id, name ,
ROW_NUMBER() OVER(PARTITION BY substring(name,PATINDEX('%)%',name)+1,20) ORDER BY name) rn
from test ) t
where rn= 1
order by 1
SQL Fiddle Link
http://www.sqlfiddle.com/#!6/a02b0/34

how to pivot multiple records

This is my table structure !
create table t(floor int,apt int)
insert into t values(1,1),(1,2),(1,4),(2,5),(2,6),(2,7)
I want to get like this!
floor room1 room2 room3
1 1 2 4
2 5 6 7
Use a PIVOT in this case.
SELECT * FROM
(
SELECT floor,
apt,
NumberedApt = 'room' + CAST(ROW_NUMBER() OVER
(PARTITION BY floor ORDER BY apt) AS NVARCHAR(100))
FROM t
) AS OrderApts
PIVOT (MAX(apt) FOR Numberedapt IN (room1, room2, room3)) AS PivotedApts
Here is and SQLFiddle of the above working.
If you are going to get many more 'room' columns then you might want to consider using a dynamic pivot, but they can be inefficient due to not having a query plan.
More on pivot here
1.you need to use Row_number() partition by floor to get row then pivot to get your requirement
select p.floor,p.[1] as room1,p.[2] as room2,p.[3] as room3 from
(
select floor,apt,row_number() over(partition by floor order by apt) as rn from #t) as t
pivot
(
min(t.apt)
for t.rn in([1],[2],[3])
)as p;
See in Action