add custom rows in the select statemen in sql - sql

I have a sql statement that combines values from a row from table and the final result has one column with a computed string.Example:
select Value1 + ' and ' + Value2 +' and another string' from MyTable
and the result would be
m1 and n1 and another string
m1 and n2 and another string
How can I update my query to add a fixed string on each row after the computed value from my table. I want to have something like(the new string needs to be on a new line):
m1 and n1 and another string
test
m1 and n2 and another string
test
I'm using sql server 2014.

You need to cross apply the extra row with a values table constructor:
select v.Value
from MyTable t
cross apply (values
(Value1 + ' and ' + Value2 +' and another string'),
('test')
) as v(Value)
Each row goes inside a set of (), columns separated by , and doing it as an apply instead of join means you can access outer columns.

You'll need an ordering mechanism to guarantee reproducible order of your output. Here is one way
with cte1 (value1, value2) as
(select 'm1', 'n1'
union all
select 'm1', 'n2'),
cte2 (col_1, row_num) as
(select value1 + 'and' + value2 + 'another string', row_number() over (order by value1)
from cte1),
cte3 (col_1, row_num) as
(select col_1, row_num
from cte2
union all
select 'test', row_num + 0.5 --to sandwich the 'test' between rows
from cte2)
select col_1
from cte3
order by row_num;
If you wish to use a more compact version
select col_1
from (select *, value1 + 'and' + value2 + 'another string' as col_1
from t
union all
select *, 'test'
from t) a
order by value1, value2, case when col_1 = 'test' then 1 else 0 end asc;

Related

SQL how to count each value in multiple columns and same rows?

COL1
COL2
COL3
A
B
A
C
D
C
for example lets say I have a dataset like this. I want to count the values, each value in multiple columns and same rows. As a result it has to say the count of the values I put into.
2A 1B and
2C 1D
Anyone can help?
You don't count values in a row, you count values in a column. So, you use sql to reformat your data in to a single column, then count the values in the usual way.
SELECT
column_value,
COUNT(*)
FROM
(
SELECT col1 AS column_value FROM your_table
UNION ALL
SELECT col2 AS column_value FROM your_table
UNION ALL
SELECT col3 AS column_value FROM your_table
)
AS pivoted
GROUP BY
column_value
ORDER BY
column_value
As I commented, here is the code for the same. Can be optimized a bit by removing multiple select statements.
Declare #val Varchar(MAX);
Select #val=COALESCE(#val + ' ' + result, result)
FROM (
SELECT CONCAT(cnt,col) result FROM (
SELECT col, count(*)cnt FROM (
SELECT col
FROM
(
SELECT col1, col2, col3
from #temp
) AS cp
UNPIVOT
(
col FOR cols IN (col1, col2, col3 )
) AS up)t
group by col)t)t2
select #val

SQL Substring to fetch values which inside Bracket only i.e. ()

Might be easy for you expert but I am finding a challenge here-
My column data is as like below, I need to separate out the value which is inside bracket(). My string pattern would always be like this.
J Zeneta (A50103050); S Rao (B499487)
Output should be
Col1 Col2
A50103050 B499487
You can try this, it might need tweaking depending on your RDBMS, this is for SQLServer
select Left(value, CharIndex(')',value)-1) from (
select value from String_Split('J Zeneta (A50103050); S Rao (B499487)','(')
where value like '%)%'
)x
Edit
To have columns a simple case can yeild, like so
select max(case when rn=1 then Value end) Col1, max(case when rn=2 then value end) Col2 from (
select Left(value, CharIndex(')',value)-1) [Value], Row_Number() over (order by (select null)) rn from (
select value from String_Split('J Zeneta (A50103050); S Rao (B499487)','(')
where value like '%)%'
)x
)x
Edit 2
Using data from an existing table example
create table #Test (id int, col varchar(50))
insert into #Test select 1, 'J Zeneta (A50103050); S Rao (B499487)'
insert into #Test select 2, 'Bob Builder (12345); Mr Rambo (67890)'
select id, max(case when (rn % 2)=0 then Value end) Col1, max(case when (rn % 2)!=0 then value end) Col2 from (
select id, Left(value, CharIndex(')',value)-1) [Value], Row_Number() over (order by (select null)) rn from (
select id, value
from #Test t cross apply String_Split(t.col,'(')
where value like '%)%'
)x
)x
group by id

PostgreSQL order in recursive query

I try to get result of my query in natural order, but have a fail.
create table Tab2 (id int, F1 varchar(100));
insert into Tab2 values(1, '10,56,657,34,767,71');
insert into Tab2 values(3, '1,5487,27,9');
insert into Tab2 values(4, '11,13,37,2');
insert into Tab2 values(2, '12,6,65,8,67,22,70,5');
WITH RECURSIVE etc (id, DataItem, F1) AS (
(SELECT id,
LEFT(F1, strpos(concat(F1, ','), ',')-1) AS Part,
overlay(F1 placing '' from 1 for strpos(concat(F1, ','),',')) AS Remainder
FROM Tab2
--ORDER BY Remainder
)
UNION ALL
(SELECT id,
LEFT(F1, strpos(concat(F1, ','), ',')-1),
overlay(F1 placing '' from 1 for strpos(concat(F1, ','),','))
FROM etc e
WHERE F1 > ''
--ORDER BY Dataitem
)
)
SELECT id, row_number() over(partition BY id ORDER BY id) num, DataItem from etc ORDER BY id;
http://sqlfiddle.com/#!15/b0ccc6/89/0
Where is my mistake?
If I understand your query correctly you are trying to get all elements from your (badly designed) comma separated string. There is no need to use a recursive query for that.
You can convert the string to array which can then be "unnested" into rows. Using the option with ordinality will also return the index of each element in the array which can be used in an order by to preserve the original order of the items in the string.
select t2.id, i.num, i.dataitem
from tab2 t2
cross join unnest(string_to_array(f1,',')) with ordinality as i(dataitem, num)
order by t2.id, i.num;
Online example
Assuming that you want to get DataItem in order, in which it is placed in comma separated string, you can use another field to get an "index" (in below example it's a rowno).
For example:
id, dataitem
1, 10
1, 56
1, 657
...
1, 71
2, 12
...
2, 5
etc.
See:
WITH RECURSIVE etc (id, rowno, DataItem, F1) AS (
(SELECT id, 1 as rowno,
LEFT(F1, strpos(concat(F1, ','), ',')-1) AS Part,
overlay(F1 placing '' from 1 for strpos(concat(F1, ','),',')) AS Remainder
FROM Tab2
)
UNION ALL
(SELECT id, rowno +1 as rowno,
LEFT(F1, strpos(concat(F1, ','), ',')-1),
overlay(F1 placing '' from 1 for strpos(concat(F1, ','),','))
FROM etc e
WHERE F1 > ''
)
)
SELECT id, DataItem
from etc
ORDER BY id, RowNo;
SqlFiddle (after changes)

Sum the two lowest values from a record

I have a table like this:
I need to sum the two lowest values for each record. For example, in the first row 2 and 4 (2 + 4 = 6).
I can find the lowest value for each row using CROSS APPLY, but I can't find the two lowest values at once to sum them.
Thanks in advance.
I would do this as:
select id, sumval - maxval
from t cross apply
(select sum(val) as sumval, max(val) as maxval
from values (value1), (value2), (value3)) v(val)
) v;
If you have three items, the sum of the smallest two is the sum of all of them minus the largest.
More generally, I would use something like this:
select id, sum2
from t cross apply
(select sum(val) as sum2
from (select top (2) val
from values (value1), (value2), (value3) v(val)
order by val asc
) v
) v
SELECT
IIF (VALUE1 < VALUE3 AND VALUE2 < VALUE3,
VALUE1 + VALUE2,
IIF(VALUE1 < VALUE2 AND VALUE3 < VALUE2,
VALUE1 + VALUE3,
IIF(VALUE3 < VALUE1 AND VALUE2 < VALUE1,
VALUE2 + VALUE3, 0)))
-- You will have to decide what to do if none of the conditions are met: I set the result to zero. This gets unwieldy if you add more columns
Initial data:
DECLARE #Table TABLE (ID INT IDENTITY(1,1),Value1 INT, Value2 INT, Value3 INT);
INSERT INTO #Table (Value1,Value2,Value3) VALUES
(2,4,5)
,(3,7,2)
,(9,1,6)
;
The code:
SELECT a.ID,SUM(a.[Value]) AS [Sum]
FROM (
SELECT p.ID,p.Value
,ROW_NUMBER()OVER(PARTITION BY p.ID ORDER BY p.Value ASC) AS [rn]
FROM #Table t
UNPIVOT(Value FOR Param IN ([Value1],[Value2],[Value3])) p
) a
WHERE a.rn <= 2 /*pick up only two lowest*/
GROUP BY a.ID
;

SQL Server convert columns to rows

I have a sql table with current value and previous value.
Id Value1 PValue1 Value2 PValue2
1 A A V V1
2 B B1 W W1
3 C C1 X X
I want to compare them and display in a the following table if the value has changes.
Id Column Value Pvalue
1 Value2 V V1
2 Value1 B B1
2 Value2 W W1
3 Value1 C C1
Is it possible in SQL 2008 without looping each column?
You can use a CROSS APPLY to unpivot the data:
SELECT t.id,
x.Col,
x.Value,
x.PValue
FROM YourTable t
CROSS APPLY
(
VALUES
('Value1', t.Value1, t.PValue1),
('Value2', t.Value2, t.PValue2)
) x (Col, Value, PValue)
where x.Value <> x.PValue;
See SQL Fiddle with Demo.
Just because I love using the pivot function, here is a version that uses both the unpivot and the pivot functions to get the result:
select id,
colname,
value,
pvalue
from
(
select id,
replace(col, 'P', '') colName,
substring(col, 1, PatIndex('%[0-9]%', col) -1) new_col,
val
from yourtable
unpivot
(
val
for col in (Value1, PValue1, Value2, PValue2)
) unpiv
) src
pivot
(
max(val)
for new_col in (Value, PValue)
) piv
where value <> pvalue
order by id
See SQL Fiddle with Demo
Here is an easy way:
SELECT Id,
'Value1' [Column],
Value1 Value,
PValue1 PValue
FROM YourTable
WHERE ISNULL(Value1,'') != ISNULL(PValue1,'')
UNION ALL
SELECT Id,
'Value2' [Column],
Value2 Value,
PValue2 PValue
FROM YourTable
WHERE ISNULL(Value2,'') != ISNULL(PValue2,'')
How about using a union:
SELECT * FROM
(SELECT Id, 'Value1' [Column], Value1 [Value], PValue1 [PValue]
FROM table_name
UNION ALL
SELECT Id, 'Value2' [Column], Value2 [Value], PValue2 [PValue]
FROM table_name)tmp
WHERE Value != PValue
ORDER BY Id
Finally, and for completeness, there is an UNPIVOT command. However, since you have two columns you want to unpivot, it'd probably be simpler to use one of the other solutions.