How to select a single row multiple times in PostgreSql - sql

I want to print 4 times the same row in PostgreSQL, how to achieve that ?
Table : mytable
Id | name
------------
1 | foo
2 | bar
3 | zzz
I want something like
Select 4x mytable.* from mytable where id=1
And the result should be
Id | name
------------
1 | foo
1 | foo
1 | foo
1 | foo

You can cross join against generate_series(1,4), which will return a table containing the numbers 1 to 4:
SELECT mytable.*
FROM mytable
CROSS JOIN generate_series(1,4) as x
WHERE id=1
For each row in your original result set, there will be one copy with 1 next to it, one with 2, and so on.

you can use generate_series.
sample:
t=# create table so48 (i int,n text);
CREATE TABLE
t=# insert into so48 select 1,'a';
INSERT 0 1
t=# insert into so48 select 2,'b';
INSERT 0 1
select:
t=# with s as (select generate_series(1,4,1) g) select so48.* from so48 join s on true where i = 1;
i | n
---+---
1 | a
1 | a
1 | a
1 | a
(4 rows)

use union all
Select mytable.* from mytable where id=1
union all Select mytable.* from mytable where id=1
union all Select mytable.* from mytable where id=1
union all Select mytable.* from mytable where id=1

Cross join should do the job
Select 4x mytable.* from mytable where id=1
cross join
(select 1 from dual union all
select 1 from dual union all
select 1 from dual union all
select 1 from dual )

Related

SQL theory: Filtering out duplicates in one column, picking lowest value in other column

I am trying to figure out the best way to remove rows from a result set where either the value in one column or the value in a different column has a duplicate in the result set.
Imagine the results of a query are as follows:
a_value | b_value
-----------------
1 | 1
2 | 1
2 | 2
3 | 1
4 | 3
5 | 2
6 | 4
6 | 5
What I want to do is:
Eliminate all rows that have duplicate values in a_value
Pick only 1 row for a given b_value
So I'd want the filtered results to end up like this after eliminating a_value duplicates:
a_value | b_value
-----------------
1 | 1
3 | 1
4 | 3
5 | 2
And then like this after picking only a single b_value:
a_value | b_value
-----------------
1 | 1
4 | 3
5 | 2
I'd appreciate suggestions on how to accomplish this task in an efficient way via SQL.
with
q_res ( a_value, b_value ) as (
select 1, 1 from dual union all
select 2, 1 from dual union all
select 2, 2 from dual union all
select 3, 1 from dual union all
select 4, 3 from dual union all
select 5, 2 from dual union all
select 6, 4 from dual union all
select 6, 5 from dual
)
-- end test data; solution begins below
select min(a_value) as a_value, b_value
from (
select a_value, min(b_value) as b_value
from q_res
group by a_value
having count(*) = 1
)
group by b_value
order by a_value -- ORDER BY is optional
;
A_VALUE B_VALUE
------- -------
1 1
4 3
5 2
1) In the inner query I am avoiding all duplicates which are present in a_value
column and getting all the remaining rows from input table and storing them
as t2. By joining t2 with t1 there would be full data without any dups as per
your #1 in requirement.
SELECT t1.*
FROM Table t1,
(
SELECT a_value
FROM Table
GROUP BY a_value
HAVING COUNT(*) = 1
) t2
WHERE t1.a_value = t2.a_value;
2) Once the filtered data is obtained, I am assigning rank to each row in the filtered dataset obtained in step-1 and I am selecting only rows with rank=1.
SELECT X.a_value,
X.b_value
FROM
(
SELECT t1.*,
ROW_NUMBER() OVER ( PARTITION BY t1.b_value ORDER BY t1.a_value,t1.b_value ) AS rn
FROM Table t1,
(
SELECT a_value
FROM Table
GROUP BY a_value
HAVING COUNT(*) = 1
) t2
WHERE t1.a_value = t2.a_value
) X
WHERE X.rn = 1;

How to comapre two columns of a table in sql?

In a table there are two columns:
-----------
| A | B |
-----------
| 1 | 5 |
| 2 | 1 |
| 3 | 2 |
| 4 | 1 |
-----------
Want a table where if A=B then
-------------------
|Match | notMatch|
-------------------
| 1 | 5 |
| 2 | 3 |
| Null | 4 |
-------------------
How can i do this?
I tried something which shows the Matched part
select distinct C.A as A from Table c inner join Table d on c.A=d.B
Try this:
;WITH TempTable(A, B) AS(
SELECT 1, 5 UNION ALL
SELECT 2, 1 UNION ALL
SELECT 3, 2 UNION ALL
SELECT 4, 1
)
,CTE(Val) AS(
SELECT A FROM TempTable UNION ALL
SELECT B FROM TempTable
)
,Match AS(
SELECT
Rn = ROW_NUMBER() OVER(ORDER BY Val),
Val
FROM CTE c
GROUP BY Val
HAVING COUNT(Val) > 1
)
,NotMatch AS(
SELECT
Rn = ROW_NUMBER() OVER(ORDER BY Val),
Val
FROM CTE c
GROUP BY Val
HAVING COUNT(Val) = 1
)
SELECT
Match = m.Val,
NotMatch= n.Val
FROM Match m
FULL JOIN NotMatch n
ON n.Rn = m.Rn
Try with EXCEPT, MINUS and INTERSECT Statements.
like this:
SELECT A FROM TABLE1 INTERSECT SELECT B FROM TABLE1;
You might want this:
SELECT DISTINCT
C.A as A
FROM
Table c
LEFT OUTER JOIN
Table d
ON
c.A=d.B
WHERE
d.ID IS NULL
Please Note that I use d.ID as an example because I don't see your schema. An alternate is to explicitly state all d.columns IS NULL in WHERE clause.
Your requirement is kind of - let's call it - interesting. Here is a way to solve it using pivot. Personally I would have chosen a different table structure and another way to select data:
Test data:
DECLARE #t table(A TINYINT, B TINYINT)
INSERT #t values
(1,5),(2,1),
(3,2),(4,1)
Query:
;WITH B AS
(
( SELECT A FROM #t
EXCEPT
SELECT B FROM #t)
UNION ALL
( SELECT B FROM #t
EXCEPT
SELECT A FROM #t)
), A AS
(
SELECT A val
FROM #t
INTERSECT
SELECT B
FROM #t
), combine as
(
SELECT val, 'A' col, row_number() over (order by (select 1)) rn FROM A
UNION ALL
SELECT A, 'B' col, row_number() over (order by (select 1)) rn
FROM B
)
SELECT [A], [B]
FROM combine
PIVOT (MAX(val) FOR [col] IN ([A], [B])) AS pvt
Result:
A B
1 3
2 4
NULL 5

How to duplicate each row in sql query?

Suppose we have a query
SELECT * FROM my_table ORDER BY id
which results in
id | title
-----------
1 | 'ABC'
2 | 'DEF'
3 | 'GHI'
How could I modify given select statement to have each row duplicated in the result set like this:
id | title
-----------
1 | 'ABC'
1 | 'ABC'
2 | 'DEF'
2 | 'DEF'
3 | 'GHI'
3 | 'GHI'
Try this...
SELECT * FROM my_table
UNION ALL
SELECT * FROM my_table
ORDER BY id
You can use union all, but I like using cross join:
select *
from MyTable cross join
(select 1 from dual union all select 2 from dual) n
order by id;
The reason I like the cross join is in the case where MyTable is really some complicated subquery. Although the query optimizer might evaluate it only once, you can't really depend on that fact. So the performance should be better in this case.
You could cross join to a row generator, the numeric value indicates how many duplicates per original you want.
select *
from my_table
cross join
(select null
from dual
connect by level <= 2)
order by id

tSQL UNPIVOT of comma concatenated column into multiple rows

I have a table that has a value column. The value could be one value or it could be multiple values separated with a comma:
id | assess_id | question_key | item_value
---+-----------+--------------+-----------
1 | 859 | Cust_A_1 | 1,5
2 | 859 | Cust_B_1 | 2
I need to unpivot the data based on the item_value to look like this:
id | assess_id | question_key | item_value
---+-----------+--------------+-----------
1 | 859 | Cust_A_1 | 1
1 | 859 | Cust_A_1 | 5
2 | 859 | Cust_B_1 | 2
How does one do that in tSQL on SQL Server 2012?
We have a user defined function that we use for stuff like this that we called "split_delimiter":
CREATE FUNCTION [dbo].[split_delimiter](#delimited_string VARCHAR(8000), #delimiter_type CHAR(1))
RETURNS TABLE AS
RETURN
WITH cte10(num) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,cte100(num) AS
(
SELECT 1
FROM cte10 t1, cte10 t2
)
,cte10000(num) AS
(
SELECT 1
FROM cte100 t1, cte100 t2
)
,cte1(num) AS
(
SELECT TOP (ISNULL(DATALENGTH(#delimited_string),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM cte10000
)
,cte2(num) AS
(
SELECT 1
UNION ALL
SELECT t.num+1
FROM cte1 t
WHERE SUBSTRING(#delimited_string,t.num,1) = #delimiter_type
)
,cte3(num,[len]) AS
(
SELECT t.num
,ISNULL(NULLIF(CHARINDEX(#delimiter_type,#delimited_string,t.num),0)-t.num,8000)
FROM cte2 t
)
SELECT delimited_item_num = ROW_NUMBER() OVER(ORDER BY t.num)
,delimited_value = SUBSTRING(#delimited_string, t.num, t.[len])
FROM cte3 t;
GO
It will take a varchar value up to 8000 characters and will return a table with the delimited elements broken into rows. In your example, you'll want to use an outer apply to turn those delimited values into separate rows:
SELECT my_table.id, my_table.assess_id, question_key, my_table.delimited_items.item_value
FROM my_table
OUTER APPLY(
SELECT delimited_value AS item_value
FROM my_database.dbo.split_delimiter(my_table.item_value, ',')
) AS delimited_items

sql range operator

Is there a SQL construct or a trick to do something like:
SELECT i WHERE i BETWEEN 0 AND 10;
?
My first idea is to create a temporary table such as:
CREATE TABLE _range ( i INT PRIMARY KEY );
and fill it
INSERT INTO _range VALUES 0;
INSERT INTO _range VALUES 1;
etc.
Is there a better way?
UPDATE:
I use sqlite in this particular case but i am interested in general answer.
What DB are you using? The between operator generally is legal syntax for SQL. We use it all the time for date ranges.
from http://www.w3schools.com/Sql/sql_between.asp
SELECT column_name(s)
FROM table_name
WHERE column_name
BETWEEN value1 AND value2
Very interesting question. Here's an ugly hack that probably is useless unless your ranges are really that small...
select * from (
select 1 as num UNION
select 2 as num UNION
select 3 as num UNION
select 4 as num UNION
select 5 as num UNION
select 6 as num UNION
select 7 as num UNION
select 8 as num UNION
select 9 as num UNION
select 10 as num
) t ;
+-----+
| num |
+-----+
| 1 |
| 2 |
....
| 9 |
| 10 |
+-----+
10 rows in set (0.00 sec)
Edit: Ok, so I got to thinking why not use cross joins. So, here is another hack and this one will quickly net you pretty large in memory tables and is perhaps reasonably good.
select POW(2,0)*t0.num + POW(2,1)*t1.num + POW(2,2)*t2.num + POW(2,3)*t3.num
as num
from (
select 0 as num UNION
select 1 as num
) t0, (
select 0 as num UNION
select 1 as num
) t1, (
select 0 as num UNION
select 1 as num
) t2, (
select 0 as num UNION
select 1 as num
) t3
order by num ;
+------+
| num |
+------+
| 0 |
| 1 |
....
| 14 |
| 15 |
+------+
16 rows in set (0.00 sec)
Will easily go to any power of 2 and should be fast enough.
with MS SQL you could use CTE :
;with numbs as
(
select 1 as col
union all
select col + 1 from numbs
where col < 10
)
select * from numbs
An SQL syntax that multiply records is CROSS JOIN
I am not sure from your request and comments, but I guess you are trying to do that.
I have done a similar thing to populate a table with a datestamp as string "YYYYMM" for a period of 20 years.
You did not specify the dbms you use, but with Oracle you could use CONNECT BY:
SELECT ROWNUM-1 i
FROM dual
CONNECT BY ROWNUM <= 10 + 1