how to do permutations combined with permutations in sql - sql

I have created a table that does all the 3 letter combinations of the alphabet. See below
ID 1stLetter 2ndLetter 3rdLetter
1 A B C
2 A B D
3 A B E
and so on
I have a second table as follows:
Letter Number
A 0
A 1
B 0
B 1
C 0
D 0
D 1
E 0
E 1
E 2
I have been trying to figure out how to combine the two so that for each row of the first table it is combined with the second table to get all possible combinations. For example, the output should look like:
NEWID ID 1stLetter 2ndLetter 3rdLetter 1stNumber 2ndNumber 3rd Number
1 1 A B C 0 0 0
2 1 A B C 1 0 0
3 1 A B C 0 1 0
4 1 A B C 1 1 0
5 2 A B D 0 0 0
6 2 A B D 0 0 1
7 2 A B D 0 1 0
8 2 A B D 0 0 1
9 2 A B D 1 0 0
10 2 A B D 1 0 1
11 2 A B D 1 1 0
12 2 A B D 1 0 1
13 2 A B D 1 1 1
14 3 A B E and so on
Is this possible? Any help will be greatly appreciated.
Thanks,
J

This should do the trick, hopefully the code is self explanatory, please ask if not:
CREATE TABLE #combo
(
id INT ,
letter1 NVARCHAR(1) ,
letter2 NVARCHAR(1) ,
letter3 NVARCHAR(1)
);
CREATE TABLE #numbers
(
letter NVARCHAR(1) ,
number INT
);
INSERT INTO #combo
( id, letter1, letter2, letter3 )
VALUES ( 1, 'A', 'B', 'C' ),
( 2, 'A', 'B', 'D' ),
( 3, 'A', 'B', 'E' );
INSERT INTO #numbers
( letter, number )
VALUES ( 'A', 0 ),
( 'A', 1 ),
( 'B', 0 ),
( 'B', 1 ),
( 'C', 0 ),
( 'C', 1 ),
( 'D', 0 ),
( 'D', 1 ),
( 'E', 0 ),
( 'E', 1 ),
( 'E', 2 );
SELECT c.* ,
n1.number ,
n2.number ,
n3.number
FROM #combo c
INNER JOIN #numbers n1 ON c.letter1 = n1.letter
INNER JOIN #numbers n2 ON c.letter2 = n2.letter
INNER JOIN #numbers n3 ON c.letter3 = n3.letter
ORDER BY id;
DROP TABLE #combo;
DROP TABLE #numbers;

Jus use CROSS JOIN
SELECT * FROM [data source1] CROSS JOIN [data source2]

Related

Cross table query on a single queston

Here's a table
A B C D R
'a' 1 3 1 0
'a' 2 3 1 1
'a' 2 3 1 0
'b' 1 3 1 1
'b' 2 4 3 2
'b' 1 4 3 0
'c' 2 4 3 0
The cross tabulation of R with respect to A is as follows:
A R count
a 0 2
a 1 1
a 2 0
b 0 1
b 1 1
b 2 1
c 0 1
c 1 0
c 2 0
The cross tabulation gives the frequency of R's value depending on A.
What is the sql query for this operation?
I would use CROSS JOIN and LEFT JOIN
select ta.a, tr.r, count(t.a)
from (select distinct a from tab) TA
cross join (select distinct r from tab) TR
left join tab t on t.a = ta.a and t.r = tr.r
group by ta.a, tr.r
Using CROSS JOIN and a conditional sum to achieve the count:
declare #Table table (A char(1), B int, C int, D int, R int)
Insert into #Table values
('a', 1, 3, 1, 0)
, ('a', 2, 3, 1, 1)
, ('a', 2, 3, 1, 0)
, ('b', 1, 3, 1, 1)
, ('b', 2, 4, 3, 2)
, ('b', 1, 4, 3, 0)
, ('c', 2, 4, 3, 0)
select A, x.R, Sum(iif(x.r = t.R, 1, 0))
from #Table t
cross join (Select distinct R from #Table) x
group by A, x.R
order by a, x.R

MS SQL.Summation of various values across columns

Table T1 has 3 columns as C1, C2 and C3 having values as R, G, B
C1 C2 C3
R R R
R R R
G R R
G G R
B G B
B B B
I want a new table in the below structure:
R G B
9 4 5
In the above table, the distinct values of the Table T1 has to be displayed as the column name and the total count of the R, G, B values from the whole table has to be displayed.
Use the COUNT aggregation function on each column with a CASE expression to filter by the correct character value:
SQL Fiddle
Oracle and/or MS SQL Server Setup:
CREATE TABLE table_name(
C1 CHAR(1),
C2 CHAR(1),
C3 CHAR(1)
);
INSERT INTO table_name VALUES ( 'R', 'R', 'R' );
INSERT INTO table_name VALUES ( 'R', 'R', 'R' );
INSERT INTO table_name VALUES ( 'G', 'R', 'R' );
INSERT INTO table_name VALUES ( 'G', 'G', 'R' );
INSERT INTO table_name VALUES ( 'B', 'G', 'B' );
INSERT INTO table_name VALUES ( 'B', 'B', 'B' );
Query 1:
SELECT COUNT( CASE C1 WHEN 'R' THEN 1 END )
+ COUNT( CASE C2 WHEN 'R' THEN 1 END )
+ COUNT( CASE C3 WHEN 'R' THEN 1 END ) AS R,
COUNT( CASE C1 WHEN 'G' THEN 1 END )
+ COUNT( CASE C2 WHEN 'G' THEN 1 END )
+ COUNT( CASE C3 WHEN 'G' THEN 1 END ) AS G,
COUNT( CASE C1 WHEN 'B' THEN 1 END )
+ COUNT( CASE C2 WHEN 'B' THEN 1 END )
+ COUNT( CASE C3 WHEN 'B' THEN 1 END ) AS B
FROM table_name
Results:
| R | G | B |
|---|---|---|
| 9 | 4 | 5 |
Query 2 or you can use UNPIVOT:
SELECT COUNT( CASE value WHEN 'R' THEN 1 END ) AS R,
COUNT( CASE value WHEN 'G' THEN 1 END ) AS G,
COUNT( CASE value WHEN 'B' THEN 1 END ) AS B
FROM table_name
UNPIVOT ( value FOR id IN ( C1, C2, C3 ) ) AS u -- Do not need AS keyword in Oracle
Results:
| R | G | B |
|---|---|---|
| 9 | 4 | 5 |

To create a column Summing the values from another column in the same view

View:
A | B
10 1
15 2
12 3
5 2
2 1
2 1
Output View:
A | B | C
10 1 14
15 2 20
12 3 12
5 2 20
2 1 14
2 1 14
I need to sum the values from column A based on column B. So, all the values from column B having value 1 extract values from column A and then sum it to column C.
I don't see the point, but:
SELECT t.a
,t.b
,sumtab.c
FROM [yourtable] t
INNER JOIN (
SELECT t.b
,sum(t.a) AS C
FROM [yourtable] t
GROUP BY t.b
) AS sumtab
ON t.b = sumtab.b
You could use SUM() OVER like this
DECLARE #SampleData AS TABLE
(
A int,
B int
)
INSERT INTO #SampleData
(
A,
B
)
VALUES
( 10, 1),
( 15, 2),
( 12, 3),
( 5 , 2),
( 2 , 1),
( 2 , 1)
SELECT *,
sum(sd.A) OVER(PARTITION BY sd.B) AS C
FROM #SampleData sd
Returns
A B C
-----------
10 1 14
2 1 14
2 1 14
15 2 20
5 2 20
12 3 12

SQL Server Query- How to Prune a table

I have a Table 'L2'
Itemset Itemset2
1 3
2 3
2 5
3 5
I created a [combination in pair of three] for these values in columns in table 'c3'
Itemset Itemset2 itemset3
1 3 5
2 3 5
1 2 3
1 2 5
Like in Apriori I want to prune the table C3.
i.e. Getting this table as output 'C3Prune'
Itemset Itemset2 itemset3
2 3 5
I want to create a SQL Server query for the same, I tried loops but it's not correct.
2 ways are provided in this answer, I want to give another query with using of UNION and EXCEPT:
select *
from C3
where not exists
(
select c3.itemset a, c3.itemset2 b
union
select c3.itemset a, c3.itemset3 b
union
select c3.itemset2 a, c3.itemset3 b
except
select itemset a, itemset2 b from l2
)
Output:
2 3 5
SQLFIDDLE DEMO
Try this:
DECLARE #L2 TABLE ( I1 INT, I2 INT )
DECLARE #C3 TABLE ( I1 INT, I2 INT, I3 INT )
INSERT INTO #L2
VALUES ( 1, 3 ),
( 2, 3 ),
( 2, 5 ),
( 3, 5 )
INSERT INTO #C3
VALUES ( 1, 3, 5 ),
( 2, 3, 5 ),
( 1, 2, 3 ),
( 1, 2, 5 )
--Version 1
SELECT c.*
FROM #C3 c
JOIN #L2 l1 ON c.I1 = l1.I1 AND c.I2 = l1.I2
JOIN #L2 l2 ON c.I1 = l2.I1 AND c.I3 = l2.I2
JOIN #L2 l3 ON c.I2 = l3.I1 AND c.I3 = l3.I2
--Version 2
SELECT * FROM #C3 c
WHERE
EXISTS(SELECT * FROM #L2 WHERE I1 = c.I1 AND I2 = c.I2) AND
EXISTS(SELECT * FROM #L2 WHERE I1 = c.I1 AND I2 = c.I3) AND
EXISTS(SELECT * FROM #L2 WHERE I1 = c.I2 AND I2 = c.I3)
Output:
I1 I2 I3
2 3 5

SQL pad query result for missing groups

Assume the following table:
TableA:
ID GroupName SomeValue
1 C 1
2 C 1
2 B 1
2 A 1
I need to construct a query that selects the following result:
ID GroupName SomeValue
1 C 1
1 B 0
1 A 0
2 C 1
2 B 1
2 A 1
The GroupName is actually derived from TableA column's CASE expression and can take only 3 values: A, B, C.
Are the analytic functions the way to go?
EDIT
Sorry, for not mentioning it, but the ID could consist of multiple columns. Consider this example:
ID1 ID2 GroupName SomeValue
1 1 C 1
1 2 C 1
2 2 C 1
2 2 B 1
2 2 A 1
I need to pad SomeValue with 0 for each unique combination ID1+ID2. So the result should be like this:
ID1 ID2 GroupName SomeValue
1 1 C 1
1 1 B 0
1 1 A 0
1 2 C 1
1 2 B 0
1 2 A 0
2 2 C 1
2 2 B 1
2 2 A 1
EDIT2
Seems like solution, proposed by #Laurence should work even for multiple-column 'ID'. I couldn't rewrite the query proposed by #Nicholas Krasnov to conform to this requirement. But could somebody compare these solutions performance-wise? Will the analytic function work faster than 'cross join + left outer join'?
To fill in gaps, you could write a similar query using partition by clause of outer join:
SQL> with t1(ID,GroupName,SomeValue) as
2 (
3 select 1, 'C', 1 from dual union all
4 select 2, 'C', 1 from dual union all
5 select 2, 'B', 1 from dual union all
6 select 2, 'A', 1 from dual
7 ),
8 groups(group_name) as(
9 select 'A' from dual union all
10 select 'B' from dual union all
11 select 'C' from dual
12 )
13 select t1.ID
14 , g.group_name
15 , nvl(SomeValue, 0) SomeValue
16 from t1
17 partition by (t1.Id)
18 right outer join groups g
19 on (t1.GroupName = g.group_name)
20 order by t1.ID asc, g.group_name desc
21 ;
ID GROUP_NAME SOMEVALUE
---------- ---------- ----------
1 C 1
1 B 0
1 A 0
2 C 1
2 B 1
2 A 1
6 rows selected
UPDATE: Response to the comment.
Specify ID2 column in the partition by clause as well:
SQL> with t1(ID1, ID2, GroupName,SomeValue) as
2 (
3 select 1, 1, 'C', 1 from dual union all
4 select 1, 2, 'C', 1 from dual union all
5 select 2, 2, 'C', 1 from dual union all
6 select 2, 2, 'B', 1 from dual union all
7 select 2, 2, 'A', 1 from dual
8 ),
9 groups(group_name) as(
10 select 'A' from dual union all
11 select 'B' from dual union all
12 select 'C' from dual
13 )
14 select t1.ID1
15 , t1.ID2
16 , g.group_name
17 , nvl(SomeValue, 0) SomeValue
18 from t1
19 partition by (t1.Id1, t1.Id2)
20 right outer join groups g
21 on (t1.GroupName = g.group_name)
22 order by t1.ID1, t1.ID2 asc , g.group_name desc
23 ;
ID1 ID2 GROUP_NAME SOMEVALUE
---------- ---------- ---------- ----------
1 1 C 1
1 1 B 0
1 1 A 0
1 2 C 1
1 2 B 0
1 2 A 0
2 2 C 1
2 2 B 1
2 2 A 1
9 rows selected
Select
i.Id1,
i.Id2,
g.GroupName,
Coalesce(a.SomeValue, 0) As SomeValue
From
(select distinct ID1, ID2 from TableA) as i
cross join
(select distinct GroupName from TableA) as g
left outer join
tableA a
on i.ID = a.ID and g.GroupName = a.GroupName
Order By
1,
2,
3 Desc