SQL add new line if value is in second column also - sql

So I am trying to pull the data from the table to give me each score the person has and if they have two scores I would like it to be on a new line with the second score. If the user has no scores I don't want anything returned. My query returns the first score if the user has one and if they don't it returns the second one. But if the user has two scores is where i'm not sure how to return that one on a new line.
table 1
+---------+--------+--------+
| name | score1 | score2 |
+---------+--------+--------+
| jim | null | 87 |
| doug | 21 | 45 |
| brandon | null | null |
| susy | 11 | null |
+---------+--------+--------+
The result my query gives is
+------+----+
| jim | 87 |
| doug | 21 |
| susy | 11 |
+------+----+
Wanted output
+------+----+
| jim | 87 |
| doug | 21 |
| doug | 45 |
| susy | 11 |
+------+----+
The query I wrote is
SELECT
name
,COALESCE(score1, score2)
FROM
table
WHERE
score1 IS NOT NULL
OR score2 IS NOT NULL
ORDER BY
name;

Treat this as two separate queries and combine the results together with UNION ALL. You'll want UNION ALL in this case and not just UNION so you get two rows returned in the case where the person has the same score in both columns.
SELECT name, Score1 as score
FROM table1
WHERE Score1 IS NOT NULL
UNION ALL
SELECT name, Score2 as score
FROM table1
WHERE Score2 IS NOT NULL
ORDER BY name, score;

I would recommend cross apply:
SELECT t.name, v.score
FROM table t CROSS APPLY
(VALUES (score1), (score2)) v(score)
WHERE v.score IS NOT NULL
ORDER BY name;
This is usually the most efficient way to unpivot data in SQL Server.

Related

Pivot the row with column's names into a column using SQL

I have one table with 25 columns and 1 single row and I want to pivot it
and obtain a column with the names of the columns and a column with the corresponding values using SQL. But I do not know how to do it.
I have the following table:
+-------+-------+-------+-----+--------+
| cnt_0 | cnt_1 | cnt_2 | ... | cnt_25 |
+-------|-------|-------+-----|--------+
| 34. | 26 | 15 | ... | 5 |
+-------+-------+-------+-----+--------+
And I want to pivot the table and transform the row of the column names into. a column and obtain this:
+--------+--------+
| counts | amount |
+--------+--------+
| cnt_0 | 34. |
| cnt_1 | 26 |
| cnt_2 | 15 |
| ... | ... |
| cnt_25 | 5 |
+--------+--------+
Verbose, but you could use UNION ALL:
SELECT counts, amount
FROM
(
SELECT 'cnt_0' AS counts, cnt_0 AS amount, 0 AS pos UNION ALL
SELECT 'cnt_1', cnt_1, 1 UNION ALL
SELECT 'cnt_2', cnt_2, 2 UNION ALL
...
SELECT 'cnt_25', cnt_25, 25
) t
ORDER BY pos;

SQL SELECT most recently created row WHERE something is true

I am trying to SELECT the most recently created row, WHERE the ID field in the row is a certain number, so I don't want the most recently created row in the WHOLE table, but the most recently created one WHERE the ID field is a specific number.
My Table:
Table:
| name | value | num |SecondName| Date |
| James | HEX124 | 1 | Carl | 11022020 |
| Jack | JEU836 | 4 | Smith | 19042020 |
| Mandy | GER234 | 33 | Jones | 09042020 |
| Mandy | HER575 | 7 | Jones | 10052020 |
| Jack | JEU836 | 4 | Smith | 14022020 |
| Ryan | GER631 | 33 | Jacque | 12042020 |
| Sarah | HER575 | 7 | Barlow | 01022019 |
| Jack | JEU836 | 4 | Smith | 14042020 |
| Ryan | HUH233 | 33 | Jacque | 15042020 |
| Sarah | HER575 | 7 | Barlow | 02022019 |
My SQL:
SELECT name, value, num, SecondName, Date
FROM MyTable
INNER JOIN (SELECT NAME, MAX(DATE) AS MaxTime FROM MyTable GROUP BY NAME) grouped ON grouped.NAME = NAME
WHERE NUM = 33
AND grouped.MaxTime = Date
What I'm doing here, is selecting the table, and creating an INNER JOIN where I'm taking the MAX Date value (the biggest/newest value), and grouping by the Name, so this will return the newest created row, for each person (Name), WHERE the NUM field is equal to 33.
Results:
| Ryan | HUH233 | 33 | Jacque | 15042020 |
As you can see, it is returning one row, as there are 3 rows with the NUM value of 33, two of which are with the Name 'Ryan', so it is grouping by the Name, and returning the latest entry for Ryan (This works fine).
But, Mandy is missing, as you can see in my first table, she has two entries, one under the NUM value of 33, and the other with the NUM value of 7. Because the entry with the NUM value of 7 was created most recently, my query where I say 'grouped.MaxTime = Date' is taking that row, and it is not being displayed, as the NUM value is not 33.
What I want to do, is read every row WHERE the NUM field is 33, THEN select the Maximum Time inside of the rows with the value of 33.
I believe what it is doing, prioritising the Maximum Date value first, then filtering the selected fields with the NUM value of 33.
Desired Results:
| Ryan | HUH233 | 33 | Jacque | 15042020 |
| Mandy | GER234 | 33 | Jones | 09042020 |
Any help would be appreciated, thank you.
If I folow you correctly, you can filter with a subquery:
select t.*
from mytable t
where t.num = 33 and t.date = (
select max(t1.date) from mytable t1 where t1.name = t.name and t1.num = t.num
)
Look at your subquery. You want the maximum dates for num 33, but you are selecting the maximum dates independent from num.
I think you want:
select *
from mytable
where (name, date) in
(
select name, max(date)
from mytable
where num = 33
group by name
);

How to select from a table with additional where clause on a single column

I'm having trouble formulating a SQL query in Oracle. Here's my sample table:
+----+-----------+-----------+--------+
| id | start | end | number |
+----+-----------+-----------+--------+
| 1 | 21-dec-19 | 03-jan-20 | 12 |
| 2 | 23-dec-19 | 05-jan-20 | 10 |
| 3 | 02-jan-20 | 15-jan-20 | 9 |
| 4 | 09-jan-20 | NULL | 11 |
+----+-----------+-----------+--------+
And here's what I have so far:
SELECT
SUM(number) AS total_number,
SUM(number) AS total_ended_number -- (WHERE end IS NOT NULL)
FROM table
WHERE ... -- a lot of where clauses
And the desired result:
+--------------+--------------------+
| total_number | total_ended_number |
+--------------+--------------------+
| 42 | 31 |
+--------------+--------------------+
I understand I could do a separate select inside 'total_ended_number', but the initial select has a bunch of where clauses already which would need to be applied to the internal select as well.
I'm capable of formulating it in 2 separate selects or 2 nested selects with all the where clauses duplicated, but my intended goal is to not duplicate the where clauses that would both be used on the table.
You could sum over a case expression with this logic:
SELECT
SUM(number) AS total_number,
SUM(CASE WHEN end IS NOT NULL THEN number END) AS total_ended_number
FROM table
WHERE ... -- a lot of where clauses
SUM(case when "end" is not null then number else 0 end) AS total_ended_number

Applying distinct in multiple columns in SQL server

I am trying to get distinct result by only one column( message). I tried
SELECT DISTINCT
[id], [message]
FROM Example table
GROUP BY [message]
But it doesn't show desired result.
Please let me know how can I do it?
Example table:
id | Message |
-- ------------
1 | mike |
2 | mike |
3 | star |
4 | star |
5 | star |
6 | sky |
7 | sky |
8 | sky |
Result table:
id | Message |
-- ------------
1 | mike |
3 | star |
6 | sky |
Group by the column you want to be unique and use an aggregate function on the other column. You want the lowest id for every message, so use MIN()
select min(id) as id,
message
from your_table
group by message

LEFT JOINing the max/top

I have two tables from which I'm trying to run a query to return the maximum (or top) transaction for each person. I should note that I cannot change the table structure. Rather, I can only pull data.
People
+-----------+
| id | name |
+-----------+
| 42 | Bob |
| 65 | Ted |
| 99 | Stu |
+-----------+
Transactions (there is no primary key)
+---------------------------------+
| person | amount | date |
+---------------------------------+
| 42 | 3 | 9/14/2030 |
| 42 | 4 | 7/02/2015 |
| 42 | *NULL* | 2/04/2020 |
| 65 | 7 | 1/03/2010 |
| 65 | 7 | 5/20/2020 |
+---------------------------------+
Ultimately, for each person I want to return the highest amount. If that doesn't work then I'd like to look at the date and return the most recent date.
So, I'd like my query to return:
+----------------------------------------+
| person_id | name | amount | date |
+----------------------------------------+
| 42 | Bob | 4 | 7/02/2015 | (<- highest amount)
| 65 | Ted | 7 | 5/20/2020 | (<- most recent date)
| 99 | Stu | *NULL* | *NULL* | (<- no records in Transactions table)
+----------------------------------------+
SELECT People.id, name, amount, date
FROM People
LEFT JOIN (
SELECT TOP 1 person_id
FROM Transactions
WHERE person_id = People.id
ORDER BY amount DESC, date ASC
)
ON People.id = person_id
I can't figure out what I am doing wrong, but I know it's wrong. Any help would be much appreciated.
You are almost there but since there are duplicate Id in the Transaction table ,so you need to remove those by using Row_number() function
Try this :
With cte as
(Select People,amount,date ,row_number() over (partition by People
order by amount desc, date desc) as row_num
from Transac )
Select * from People as a
left join cte as b
on a.ID=b.People
and b.row_num=1
The result is in Sql Fiddle
Edit: Row_number() from MSDN
Returns the sequential number of a row within a partition of a result set,
starting at 1 for the first row in each partition.
Partition is used to group the result set and Over by clause is used
Determine the partitioning and ordering of the rowset before the
associated window function is applied.