Multiple Combinations of Values in Numerical Order - tsql

I have searched and attempted to solve this puzzle myself (I've gotten close, but I've had no luck). I have a large table of values (composed of Sets of Values) that can have multiple combinations, but those combinations must be returned in the ID order.
I have not been able to get this to work in SQL.
Example Set:
(Sorry I am not able to post an image which would explain it better so Ill keep it simple.)
Table[(ID, Value) {(1,A),(1,B),(1,C),(2,D),(3,F),(3,G), (4,J), (5,S),(5,T),(5,U))}
RESULTS
ID VALUE
1 A
2 F
3 G
4 J
5 S
1 A
2 F
3 G
4 J
5 T
1 A
2 F
3 G
4 J
5 U
1 A
2 F
3 H
4 J
5 S
1 A
2 F
3 H
4 J
5 T
1 A
2 F
3 H
4 J
5 U
1 B
2 F
3 G
4 J
5 S
1 B
2 F
3 G
4 J
5 T
1 B
2 F
3 G
4 J
5 U
1 B
2 F
3 H
4 J
5 S
1 B
2 F
3 H
4 J
5 T
1 B
2 F
3 H
4 J
5 U
1 C
2 F
3 G
4 J
5 S
1 C
2 F
3 G
4 J
5 T
1 C
2 F
3 G
4 J
5 U
1 C
2 F
3 H
4 J
5 S
1 C
2 F
3 H
4 J
5 T
1 C
2 F
3 H
4 J
5 U

Here's the problem in dynamic SQL without any cursors or loops.
IF OBJECT_ID('yourTable') IS NOT NULL
DROP TABLE yourTable;
CREATE TABLE yourTable (ID INT, Value CHAR(1));
INSERT INTO yourTable
VALUES (1,'A'),(1,'B'),(1,'C'),
(2,'D'),
(3,'F'),(3,'G'),
(4,'J'),
(5,'S'),(5,'T'),(5,'U');
DECLARE #row_number_cols VARCHAR(MAX),
#Aliased_Cols VARCHAR(MAX),
#Cross_Joins VARCHAR(MAX),
#Unpivot VARCHAR(MAX);
SELECT #row_number_cols = COALESCE(#row_number_cols + ',','') + col,
#Aliased_Cols = COALESCE(#Aliased_Cols + ',','') + CONCAT(col,' AS col',ID),
#Cross_Joins = COALESCE(#Cross_Joins,'') + CASE
WHEN ID = 1 THEN CONCAT(' FROM (SELECT * FROM yourTable WHERE ID = 1) AS ID',ID)
ELSE CONCAT(' CROSS JOIN (SELECT * FROM yourTable WHERE ID = ',ID,') AS ID',ID)
END,
#Unpivot = COALESCE(#Unpivot + ',','') + CONCAT('col',ID)
FROM yourTable A
CROSS APPLY (SELECT CONCAT('ID',ID,'.Value')) CA(col) --Just so I can reuse "col" in my code
GROUP BY A.ID,CA.col
SELECT #row_number_cols,#Aliased_Cols,#Cross_Joins,#Unpivot
SELECT
'WITH CTE_crossJoins
AS
(
SELECT ROW_NUMBER() OVER (ORDER BY ' + #row_number_cols + ') group_num,' + #Aliased_Cols +
#Cross_Joins + '
)
SELECT group_num,
val
FROM CTE_crossJoins
UNPIVOT
(
val for col IN (' + #Unpivot + ')
) unpvt
ORDER BY 1,2'
Results:
group_num val
-------------------- ----
1 A
1 D
1 F
1 J
1 S
2 A
2 D
2 G
2 J
2 S
3 A
3 D
3 G
3 J
3 T
4 A
4 D
4 F
4 J
4 T
5 A
5 D
5 F
5 J
5 U
6 A
6 D
6 G
6 J
6 U
7 B
7 D
7 G
7 J
7 S
8 B
8 D
8 F
8 J
8 S
9 B
9 D
9 F
9 J
9 T
10 B
10 D
10 G
10 J
10 T
11 B
11 D
11 G
11 J
11 U
12 B
12 D
12 F
12 J
12 U
13 C
13 D
13 F
13 J
13 S
14 C
14 D
14 G
14 J
14 S
15 C
15 D
15 G
15 J
15 T
16 C
16 D
16 F
16 J
16 T
17 C
17 D
17 F
17 J
17 U
18 C
18 D
18 G
18 J
18 U

I think this has been answered before here:
How to generate all possible data combinations in SQL?
difference being that they essentially dropped the ID column, should be easy to pull it through though.

You can employ the SQL windows function to achieve this.
;WITH CTE AS
(
SELECT Id,
Value,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID) RN
FROM Tbl
)
SELECT * FROM CTE ORDER BY RN, ID, VALUE
Fiddle

Related

SQL aggregate sum produces unexpected output

I don't understand how sum works.
For a PostgreSQL table in dbeaver:
a
b
c
d
1
2
3
2
1
2
4
3
2
1
3
2
2
1
4
2
3
2
4
2
the query
select a, b, c, d, sum(c) as sum_c, sum(d) as sum_d from abc a group by a, b, c, d
produces
a
b
c
d
sum_c
sum_d
1
2
3
2
3
2
1
2
4
3
4
3
2
1
3
2
3
2
2
1
4
2
4
2
3
2
4
2
4
2
and I don't understand why: I expected sum_c would be 18 in each row, which is the sum of values in c, and sum_d would be 11 for the same reason.
Why do sum_c and sum_d just copy the values from c and d in each row?
You can't get the result that you want with group by.
When you aggregate with group by you create groups for all the columns that are after group by and for each of these groups you get the aggregated results.
For your sample data, one group is 1,2,3,2 and for this combination of values you get the sum of c which is 3 since there is only 1 row with c=3 in that group.
Use SUM() window function:
SELECT a, b, c, d,
SUM(c) OVER () sum_c,
SUM(d) OVER () sum_d
FROM abc

SPSS Modeler group by and select top n rows

I would like to know what is the proper way in SPSS to group data by specydic column and then find top n max values.
For example I have below columns:
x<-c(3,2,1,8,7,11,10,9,7,5,4)
y<-c("a","a","a", "b","b","c","c","c","c","c","c")
z<-c(2,2,2,1,1,3,3,3,3,3,3)
I want to select top max n values from column X for each group by column y
x y
1 3 a
2 2 a
3 1 a
4 8 b
5 7 b
6 11 c
7 10 c 3
8 9 c 3
9 7 c 3
10 5 c 3
11 4 c 3

add column to table in kdb based of existing columns?

I want to add a new column to a kdb table, it should add based of the existing column by populating with the non null value as below
q)t:([]a:`a`b`c`d`e`f`g`h;b:1 0n 3 4 0n 6 0n 8;c:0n 2 0n 0n 5 0n 7 0n)
q)t
a b c
-----
a 1
b 2
c 3
d 4
e 5
f 6
g 7
h 8
I want to add a column d that would take the value from c or d that isn't null
to produce a table like this
a b c d
-------
a 1 1
b 2 2
c 3 3
d 4 4
e 5 5
f 6 6
g 7 7
h 8 8
I tried concatenating but then it has the null in it:
q)update d:(b,'c)from t
a b c d
----------
a 1 1
b 2 2
c 3 3
d 4 4
e 5 5
f 6 6
g 7 7
h 8 8
A vector conditional might be what you’re after, something like the below:
update d:?[null b;c;b] from t
You can read more about vector conditionals here. This expects a Boolean list as the first argument and returns values from a list in the second argument where True, or values from a list in the third argument where False.
For example:
q)?[10101b;”abcde”;”ABCDE”]
“aBcDe”
When used in conjunction with a select/update statement, columns of the table can be specified as the arguments to the vector conditional as these are simply lists.
As an aside, the null keyword returns a Boolean true where a value is null and is useful as part of your solution.
You can use the ^(fill) operator.
t:([]a:`a`b`c`d`e`f`g`h;b:1 0n 3 4 0n 6 0n 8;c:0n 2 0n 0n 5 0n 7 0n)
q)update d:b^c from t
a b c d
-------
a 1 1
b 2 2
c 3 3
d 4 4
e 5 5
f 6 6
g 7 7
h 8 8
It is worth noting that if you had a row with non-null values for b and c then the query above would default to the value in c. If you would prefer the value in b to be default then switch the inputs:
q)t:([]a:`a`b`c`d`e`f`g`h;b:1 0n 3 4 0n 6 0n 8;c:0n 2 0n 0n 5 100 7 0n)
q)update d:b^c from t
a b c d
-----------
a 1 1
b 2 2
c 3 3
d 4 4
e 5 5
f 6 100 100
g 7 7
h 8 8
q)update d:c^b from t
a b c d
---------
a 1 1
b 2 2
c 3 3
d 4 4
e 5 5
f 6 100 6
g 7 7
h 8 8
You could use 'or(|)' operator.
q)update d:b|c from t
Concat will give you a list with items from both 'b' and 'c' column. It will not remove null. 'or' will compare each pair of 'b' and 'c' and will return maximum value from that pair. As null is lesser than an integer, it will give you integer value either from 'b' or 'c' column.
Can use fill here - https://code.kx.com/wiki/Reference/Caret
q)t:([]a:`a`b`c`d`e`f`g`h;b:1 0n 3 4 0n 6 0n 8;c:0n 2 0n 0n 5 0n 7 0n)
q)update d:c^b from t
a b c d
-------
a 1 1
b 2 2
c 3 3
...

Reorder Table Rows and columns Matlab

I have a 5x5 table:
a b c d e
a 1 2 3 4 5
b 3 5 7 2 6
c 1 3 4 6 1
d 4 4 1 7 8
e 6 7 2 1 6
where the headers are the strings.
I want to know how to reorder the table rows and columns using the headers
so for example of I wanted them to be in this order e b c a d then this will be the table:
e b c a d
e 6 7 2 6 1
b 6 5 7 3 2
c 1 3 4 1 6
a 5 7 3 1 4
d 8 4 1 4 7
Let the table be defined as
T = table;
T.a = [1 3 1 4 6].';
T.b = [2 5 3 4 7].';
T.c = [3 7 4 1 2].';
T.d = [4 2 6 7 1].';
T.e = [5 6 1 8 6].';
And let the new desired order be
order = {'e' 'b' 'c' 'a' 'd'};
The table can be reordered using just indexing:
[~, ind] = ismember(order, T.Properties.VariableNames);
T_reordered = T(ind,order);
Note that:
To reorder only columns you'd use T_reorderedCols = T(:,order);
To reorder only rows you'd use T_reorderedRows = T(ind,:);
So in this example,
T =
a b c d e
_ _ _ _ _
1 2 3 4 5
3 5 7 2 6
1 3 4 6 1
4 4 1 7 8
6 7 2 1 6
T_reordered =
e b c a d
_ _ _ _ _
6 7 2 6 1
6 5 7 3 2
1 3 4 1 6
5 2 3 1 4
8 4 1 4 7
Here is a way to do it using indexing. You can indeed re-arrange the rows and columns using indices as you would for any array. In this case, I substitute each letter in the headers array with a number (originally [1 2 3 4 5]) and then, using a vector defining the new order [5 2 3 1 4], re-order the table. You could make some kind of lookup table to automate this when you deal with larger tables:
clc
clear
a = [1 2 3 4 5;
3 5 7 2 6;
1 3 4 6 1;
4 4 1 7 8;
6 7 2 1 6];
headers = {'a' 'b' 'c' 'd' 'e'};
%// Original order. Not used but useful to understand the idea... I think :)
OriginalOrder = 1:5;
%// New order
NewOrder = [5 2 3 1 4];
%// Create table
t = table(a(:,1),a(:,2),a(:,3),a(:,4),a(:,5),'RowNames',headers,'VariableNames',headers)
As a less cumbersome alternative to manually creating the table with the function table, you can use (thanks to #excaza) the function array2table which saves a couple steps:
t = array2table(a,'RowNames',headers,'VariableNames',headers)
Either way, re-arrange the table using the new indices:
New_t = t(NewOrder,NewOrder)
Output:
t =
a b c d e
_ _ _ _ _
a 1 2 3 4 5
b 3 5 7 2 6
c 1 3 4 6 1
d 4 4 1 7 8
e 6 7 2 1 6
New_t =
e b c a d
_ _ _ _ _
e 6 7 2 6 1
b 6 5 7 3 2
c 1 3 4 1 6
a 5 2 3 1 4
d 8 4 1 4 7

PostgreSQL, sum data from row of table?

x a b c d
----------
A 1 2 3 4
B 5 6 7 8
C 6 7 8 9
I want my sum of A = 1 + 2 + 3 + 4 and so for B and C, Is there any command that can sum row of data in PostgreSQL?
There is no such built-in function, but you can simply do the following:
select x, a+b+c+d as column_sum from mytable
Assuming, of course, that the data type of a, b, c and d are numeric.