select multiple columns count one column and group by one column in one table - sql

I have a table named [delivery], with columns [ID],[Employee],[Post],[c_name],[Deli_Date],[note]
I need to Select all columns and count Employee and then group by Employee.
data in the table like this:
---------------------------------------------------
| Employee| Post |c_name |Deli_Date |Note |
|---------|-----------|---------------------|-----|
| DAVID |MANAGER | a |11/11/2018 |note |
| DAVID |MANAGER | b |01/01/2015 |note |
| SAM |ACOUNTS | c |10/10/2016 |note |
| DAVID |IT | a |10/02/2015 |note |
| DAVID |DOCTOR | c |20/02/2017 |note |
| JAMES |DELIVERYMAN| b |05/05/2015 |note |
| OLIVER |DRIVER | b |02/02/2014 |note |
| SAM |ACOUNTS | c |02/02/2012 |note |
this code:
select Employee, count(Employee) as TIMES from delivery
group by Employee
the result is: (but I need to show the other columns too).
| Employee| TIMES |
|---------|-------|
| DAVID | 4 |
| JAMES | 1 |
| OLIVER | 1 |
| SAM | 2 |
I need my code show Like This:
| Employee| TIMES | Post |c_name |Deli_Date |Note |
|---------|-------|-----------|---------------------|-----|
| DAVID | 4 |MANAGER | a |11/11/2018 |note |
| JAMES | 1 |DELIVERYMAN| b |05/05/2015 |note |
| OLIVER | 1 |DRIVER | b |02/02/2014 |note |
| SAM | 2 |ACOUNTS | c |10/10/2016 |note |
what is the best Query could give me that result?
see columns [c_name],[Deli_Date] they shows the last inserted data.
or just give me the result without [c_name],[Deli_Date] it's ok.

If you want the last date along with the count, you can use window functions:
select d.Employee, d.cnt, d.Post, d.c_name, d.Deli_Date, d.Note
from (select d.*,
count(*) over (partition by employee) as cnt,
row_number() over (partition by employee order by deli_date desc) as seqnum
from delivery d
) d
where seqnum = 1;

You need to include all the non-aggregated columns in the select and group by clauses
select Employee,
count(Employee) as TIMES,
max(Deli_date) as LAST_DELI_DATE,
post,
note
from delivery
group by Employee, post, note
Max(Deli_date) will give you the latest date.
To get the latest c_name, note, post, etc. you will need a subquery with a rank function sorted by the deli_date. I will add the example later.

select Employee, count(Employee) as TIMES,Post,c_name,Deli_Date,Note from delivery
group by Employee

Related

SQL Group By Query With Specific First Row

I'm using this query to pull information about companies and their scores from a ms sql database.
SELECT company, avg(score) AS Value FROM Responses where id=12 group by company
This is the result
| COMPANY | VALUE |
|: ------------ | ------:|
| Competitor A | 6.09 |
| Competitor B | 5.70 |
| Other Brand | 5.29 |
| Your Brand | 6.29 |
What I need is a query that will put one company that I will specify in the first position (in this case, the company is Your Brand) and then order the rest by the company like this.
| COMPANY | VALUE |
|: ------------ | -----:|
| Your Brand | 6.29 |
| Competitor A | 6.09 |
| Competitor B | 5.70 |
| Other Brand | 5.29 |
As #jarlh has suggested, use a CASE expression to order:
SELECT company, AVG(score) AS Value
FROM Responses
WHERE id = 12
GROUP BY company
ORDER BY CASE company WHEN 'Your Brand' THEN 0 ELSE 1 END,
AVG(score) DESC;

Add column to table with set values for every row expanding the table

I'm trying to add a column to a table in Redshift that adds multiple values to all the rows but has no relation, apart from all rows should be affected.
I'm not sure how to describe this so Google-ing is proving tough!
Visual example:
+----+-------+
| ID | Name |
+----+-------+
| 1 | James |
| 2 | Jane |
+----+-------+
Should become
+----+-------+-----+
| ID | Name | Sec |
+----+-------+-----+
| 1 | James | SG1 |
| 1 | James | SG2 |
| 1 | James | SG3 |
| 2 | Jane | SG1 |
| 2 | Jane | SG2 |
| 2 | Jane | SG3 |
+----+-------+-----+
Basically added "SG1, SG2, and SG3" to every row.
Thanks,
You can cross join a derived table that contains the three values:
select t.id, t.name, s.sec
from mytable t
cross join (select 'SG1' sec union all select 'SG2' union all select 'SG3') s
I am unsure whether Redshift supports values(), which would help shortening the syntax:
select t.id, t.name, s.sec
from mytable t
cross join (values ('SG1'), ('SG2'), ('SG3')) s(sec)

SQL select values sum by same ID

here is my table called "Employee"
eID | name |
==============
1 | Mike |
2 | Josh |
3 | Mike |
And table called "Sells"
sID | eID | | price |
=========================
1 | 1 | | 8 |
2 | 3 | | 9 |
3 | 3 | | 5 |
4 | 1 | | 4 |
5 | 1 | | 3 |
This should be my expected result: returns the total income per employee
name | Income |
==================
Mike | 15 |
Josh | 0 |
Mike | 14 |
Actually, I know use the query "SUM...GROUP BY..." to get the incomes of 15 and 14, but I don't know how to get the income of 0 which is not shown on the "Sells" table.
Could someone give me some help? Thanks a lot.
You just need to use a left outer join, so you can get the sum for missing values too. You could use case expression to deal with null values
SELECT e.name,
COALESCE(SUM(price), 0) as Income
FROM employees e
LEFT OUTER JOIN sells s
ON e.eid = s.eid
GROUP BY e.eid, e.name
Edited: case expression is not needed. I put coalesce on the return of sum fuction, in order to deal with missing values (SUM over an empty set returns NULL)

Need PIVOT or CASE solution for converting columns to rows (NON-Dynamic if possible)

So I have a table that has data such as this:
SCHD_ID | INST_ID |
|---------|---------|
| 1001 | Mike |
| 1001 | Ted |
| 1001 | Chris |
| 1002 | Jill |
| 1002 | Jamie |
| 1003 | Brad |
| 1003 | Carl |
| 1003 | Drew |
| 1003 | Nick |
I need to come up with a query to display the data like below:
|SCHD_ID | INST 1 | INST 2 | INST 3 |
|---------|--------|--------|--------|
| 1001 | Mike | Ted | Chris |
| 1002 | Jill | Jamie | Null |
| 1003 | Brad | Carl | Drew |
I have tried looking into all the pivot descriptions and some case examples but everything seems to use a common repeated value to pivot around. This is one of those cases where the columns need to be dynamic, but only to a point. I can drop off any data after the third instructor. In the example above I did not put in a column for INST 4 for SCHD_ID 1003 even though in my data set example it existed. Can adding in a restraint like this make it possible to come up with a non dynamic solution for the pivot/case statement?
Thanks for the help,
Dwayne
You can do this using row_number() and conditional aggregation. However, your data doesn't have an ordering column, so you cannot guarantee which three instructors you will get:
select schd_id,
max(case when seqnum = 1 then inst_id end) as inst1,
max(case when seqnum = 2 then inst_id end) as inst2,
max(case when seqnum = 3 then inst_id end) as inst3
from (select t.*,
row_number() over (partition by schd_id order by sched_id) as seqnum
from table t
) t
group by SCHD_ID ;
If you have a priority ordering for choosing the instructors, then put the logic in the order by clause.

MySQL: How to select and display ALL rows from one table, and calculate the sum of a where clause on another table?

I'm trying to display all rows from one table and also SUM/AVG the results in one column, which is the result of a where clause. That probably doesn't make much sense, so let me explain.
I need to display a report of all employees...
SELECT Employees.Name, Employees.Extension
FROM Employees;
--------------
| Name | Ext |
--------------
| Joe | 123 |
| Jane | 124 |
| John | 125 |
--------------
...and join some information from the PhoneCalls table...
--------------------------------------------------------------
| PhoneCalls Table |
--------------------------------------------------------------
| Ext | StartTime | EndTime | Duration |
--------------------------------------------------------------
| 123 | 2010-09-05 10:54:22 | 2010-09-05 10:58:22 | 240 |
--------------------------------------------------------------
SELECT Employees.Name,
Employees.Extension,
Count(PhoneCalls.*) AS CallCount,
AVG(PhoneCalls.Duration) AS AverageCallTime,
SUM(PhoneCalls.Duration) AS TotalCallTime
FROM Employees
LEFT JOIN PhoneCalls ON Employees.Extension = PhoneCalls.Extension
GROUP BY Employees.Extension;
------------------------------------------------------------
| Name | Ext | CallCount | AverageCallTime | TotalCallTime |
------------------------------------------------------------
| Joe | 123 | 10 | 200 | 2000 |
| Jane | 124 | 20 | 250 | 5000 |
| John | 125 | 3 | 100 | 300 |
------------------------------------------------------------
Now I want to filter out some of the rows that are included in the SUM and AVG calculations...
WHERE PhoneCalls.StartTime BETWEEN "2010-09-12 09:30:00" AND NOW()
...which will ideally result in a table looking something like this:
------------------------------------------------------------
| Name | Ext | CallCount | AverageCallTime | TotalCallTime |
------------------------------------------------------------
| Joe | 123 | 5 | 200 | 1000 |
| Jane | 124 | 10 | 250 | 2500 |
| John | 125 | 0 | 0 | 0 |
------------------------------------------------------------
Note that John has not made any calls in this date range, so his total CallCount is zero, but he is still in the list of results. I can't seem to figure out how to keep records like John's in the list. When I add the WHERE clause, those records are filtered out.
How can I create a select statement that displays all of the Employees and only SUMs/AVGs the values returned from the WHERE clause?
Use:
SELECT e.Name,
e.Extension,
Count(pc.*) AS CallCount,
AVG(pc.Duration) AS AverageCallTime,
SUM(pc.Duration) AS TotalCallTime
FROM Employees e
LEFT JOIN PhoneCalls pc ON pc.extension = e.extension
AND pc.StartTime BETWEEN "2010-09-12 09:30:00" AND NOW()
GROUP BY e.Name, e.Extension
The issue is when using an OUTER JOIN, specifying criteria in the JOIN section is applied before the JOIN takes place--like a derived table or inline view. The WHERE clause is applied after the OUTER JOIN, which is why when you specified the WHERE clause on the table being LEFT OUTER JOIN'd to that the rows you still wanted to see are being filtered out.