SQL Get Union Result into different cols - sql-server

What is the best to way, to get a Union result into different cols
For example
SELECT 1 AS Col1
UNION
SELECT 2 AS Col2
Result:
| Col1 | Col2 |
| 1 | 2 |
The only way I see it, is to create a auxiliary table with two cols and insert each value in the respective col. However, I would like a cleaner and better way.
(There is no unique key between both selects, to make a JOIN)

Related

Using Group By And Over clause on Different columns

I have a table like this;
col 1|col 2|col 3
a | 2 | 10
b | -1 | 10
a | 10 | 10
The goal is to get output as;
col 1| col 2| col 3
a | 12 | 30
b | -1 |30
I tried the following query;
select col 1,
sum(col 2),
sum(col 3) OVER()
From table t1
group by col 1
But I got the error; col 3 is not a valid group by expression.
Kindly suggest an alternate solution.thanks in advance.
You may try taking the sum of SUM(col3) over the entire table:
SELECT
col1,
SUM(col2),
SUM(SUM(col3)) OVER()
FROM table t1
GROUP BY col1;
If you want to use SUM as a window function, then you need to sum something which is available after GROUP BY has evaluated. SUM(col3) is available, while col3 is not.

Resolving hierarchy in a database table

I have an org chart table which is modeled like this:
+-------------+------------+-----------------+
| Employee_ID | Manager_ID | Department_Name |
+-------------+------------+-----------------+
| 1 | 2 | Level1 |
| 2 | 3 | Level2 |
| 3 | | Level3 |
+-------------+------------+-----------------+
So, each employee refers to another row, in a chain which represents the org chart. With all employees, this model is used to represent the hierarchy.
However, for reporting purposes, we'd need to query a denormalized table, i.e. where the data is represented like this:
+-------------+--------+--------+--------+
| Employee_ID | ORG_1 | ORG_2 | ORG_3 |
+-------------+--------+--------+--------+
| 1 | Level1 | | |
| 2 | Level1 | Level2 | |
| 3 | Level1 | Level2 | Level3 |
+-------------+--------+--------+--------+
with an many ORG_x columns as needed to represent all levels that can be found. Then you can do simple groupings such as GROUP BY ORG_1, ORG_2, ORG_3. Note that one could reasonably assume the maximum number of levels.
So here's my question: since the database sits on SQL server, can I expect this to be feasible in Transact-SQL so that I could build a view?
Before I start learning T-SQL, I want to make sure I'm on the right track.
(BTW, if yes, I'd be interested in recommendations for a good tutorial!)
Thanks!
R.
I would use common table expressions with PIVOT:
DECLARE #T TABLE
(
Employee_ID int,
Manager_ID int,
Department_Name varchar(10)
);
INSERT #T VALUES
(1,2,'Level 1'),
(2,3,'Level 2'),
(3,NULL,'Level 3');
WITH C AS (
SELECT Employee_ID, Manager_ID, Department_Name
FROM #T
UNION ALL
SELECT T.Employee_ID, T.Manager_ID, C.Department_Name
FROM C
JOIN #T T ON C.Manager_ID=T.Employee_ID
), N AS (
SELECT ROW_NUMBER() OVER (PARTITION BY Employee_ID ORDER BY Department_Name) N, *
FROM C
)
SELECT Employee_ID, [1] ORG_1, [2] ORG_2, [3] ORG_3
FROM N
PIVOT (MAX(Department_Name) FOR N IN ([1],[2],[3])) P
ORDER BY Employee_ID
Result:
Employee_ID ORG_1 ORG_2 ORG_3
----------- ---------- ---------- ----------
1 Level 1 NULL NULL
2 Level 1 Level 2 NULL
3 Level 1 Level 2 Level 3
Note: If you have only 3 levels, you can also do simple 3 x JOIN
Yes the pattern you have here is known as an adjacency list. It is very common. The downside is that build your tree requires you to use recursion which can lead to performance problems on large sets. Another approach that is a lot faster is to use the Nested Sets model. It is a little less intuitive at first but once you understand the concept it is super easy.
No matter which model you use to store your data it is going to require a dynamic pivot or a dynamic crosstab to get it in the denormalized format you need.

Compare different rows of a mdx query between them

I need some help. I'm trying to compare different rows of a mdx query between them.
For example, imagine I have 2 different columns (Col1 and Col2 which are entities and they mean something like Col1 has to pay Col2) and I have 1 measure (the amount that Col1 have to pay for Col2). My query gets a result like the following.
Col1 | Col2 | Result
A | B | 20
A | C | 30
B | C | 10
B | A | -20
C | A | -30
C | B | -10
I'm not able to check for example if the amount from A to B and the amount from B to A are the same.
Can someone give me an advice ?
Thanks a lot
I think you can use a SSRS expression to determine the Result value to be paid by Col2 to Col1.
Create a new column in your tablix using this expression:
=Lookup(Fields!Col2.Value & Fields!Col1.Value,
Fields!Col1.Value & Fields!Col2.Value,Fields!Result.Value,"DataSetName")
Replace DataSetName by the actual name of yours.
It will give you the corresponding Result value:
If there is no a row for a specific Col2 - Col1 relation it will produce Nothing value.
Let me know if this helps.

SQL Counting multiple columns for same ID in same table

I have a table with columns GameID, GoalID, PlayerID, Assist1ID, Assist2ID (all integers). PlayerID translates as the ID of the person who actually scored the goal, but Assist1ID and Assist2ID also get player IDs.
I am trying to get a dataset with the distinct PlayerID's (from the PlayerID column or either of the assist columns), a count of goals (PlayerID column) and a count of assists (which is actually the sum of counting columns Assist1 and Assist2 when that playerID occurs). A PlayerID will never be in more than one of those columns.
I have been trying several approaches, mostly with UNION ALL, as well as some SUM/CASE but I am just not getting it. Should I be using a temporary table for this, or is there a way to check the rows, and if the PlayerID.
Example: (note that GoalID and GameID aren't really important in this case)
GameID | GoalID | PlayerID | Assist1ID | Assist2ID
1 | 1 | 1876 | 2098 | 1097
1 | 2 | 2098 | 1829 | 1876
1 | 3 | 2098 | 1876 | ----
My query should return:
PlayerID | Goals | Assists
1876 | 1 | 2
2098 | 2 | 1
1829 | 0 | 1
1097 | 0 | 1
etc
Is this actually possible, or will I have to do some work in the code part of things?
To make sure you get a result record for every player involved, no matter if they only played, only assisted or did both, you must go thrice through your data and glue the records together with UNION ALL. Then count.
select playerid, sum(goal) as goals, sum(assist) as assists
from
(
select playerid, 1 as goal, 0 as assist from mytable
union all
select assist1id, 0 as goal, 1 as assist from mytable
union all
select assist2id, 0 as goal, 1 as assist from mytable
)
group by playerid;
It can be done this way, but I have a feeling that there might be a simpler solution.
SELECT PlayerID, SUM(Goals), SUM(Assists)
FROM (
SELECT PlayerID,Count(*) AS Goals,0 AS Assists FROM Goals GROUP BY PlayerID UNION ALL
SELECT Assist1ID,0,Count(*) FROM Goals GROUP BY Assist1ID UNION ALL
SELECT Assist2ID,0,Count(*) FROM Goals GROUP BY Assist2ID
) T
WHERE NOT PlayerID IS NULL
GROUP BY PlayerID
SELECT x.playerid
, SUM(y.playerid = x.playerid) goals
, SUM(x.playerid IN (y.assist1id,y.assist2id)) assists
FROM
( SELECT playerID FROM my_table
UNION
SELECT assist1id FROM my_table
UNION
SELECT assist2id FROM my_table
) x
LEFT
JOIN my_table y
ON x.playerid IN(y.playerid,y.assist1id,y.assist2id)
WHERE x.playerid IS NOT NULL
GROUP
BY playerid;

How to do recursive select in PostgreSQL with array as an argument

I am trying to implement easy recursive function in PostgreSQL but I cannot finish it...
I have got table MyTable which includes columns Col1 and Col2. Data inside is like this:
Col1 | Col2
1 | 2
2 | 5
2 | 6
3 | 7
4 | 5
4 | 2
5 | 3
I would like to write a function which takes as a parameter array of Col1 f.e. (1,2) and gives me back values from Col2 like this :
1 | 2
2 | 5
2 | 6
and after that, does it again with results : (2, 5, 6)
so:
1 | 2
2 | 5
2 | 6
5 | 3
(2 is already in, and key '6' does not exist)
and again (3):
1 | 2
2 | 5
2 | 6
5 | 3
3 | 7
and for (7) nothing because value '7' does not exist in Col1.
It is an easy recursion but I have no idea how to implement it. I have got so far something like this:
with recursive aaa(params) as (
select Col1, Col2
from MyTable
where Col1 = params -- I need an array here
union all
select Col1, Col2
from aaa
)
select * from aaa;
But it of course does not work
Thanks in advance
The basic pattern for recursion is to have your base case as the first part of the union and in the second part join the recursion result to what you need to produce the next level of results. In your case it would look like this:
WITH RECURSIVE aaa(col1, col2) AS (
SELECT col1, col2 FROM mytable
WHERE col1 = ANY (ARRAY[1,2]) -- initial case based on an array
UNION -- regular union because we only want new values
SELECT child.col1, child.col2
FROM aaa, mytable AS child -- join the source table to the result
WHERE aaa.col2 = child.col1 -- the recursion condition
)
SELECT * FROM aaa;

Resources