Sql Query to group the data from two tables - asp.net

I have two tables Department and Employee.
Department table looks like this:
ID DeptName
1 IT
2 CSE
3 ECE
Employee table :
ID DeptID EmployeeName Salary
1 1 John 10000
2 1 Bob 15000
3 2 Akon 12000
4 2 Smith 20000
Now I want to group the data in such a way that I get the following results which include these columns :
ID DeptName Employee
1 IT John,10000
Bob,15000
2 CSE Akon,12000
Smith,20000
Can we do something like this using SQL group functions or any other way?
Please help me.
Thanks,
Rajbir

This:
select final.deptId, d.deptName,
e3.employeename + ',' + cast(e3.salary as varchar) employee
from employee e3
left join (
select e1.id, e1.deptId from employee e1
left join employee e2
on e1.deptId = e2.deptId and e1.id > e2.id
where e2.id is null
) final on e3.id = final.id
left join department d on d.id = final.deptId
Results in:
+--------+----------+-------------+
| DEPTID | DEPTNAME | EMPLOYEE |
+--------+----------+-------------+
| 1 | IT | John,10000 |
| | | Bob,15000 |
| 2 | CSE | Akon,12000 |
| | | Smith,20000 |
+--------+----------+-------------+
Note that the "blank" values are actually filled with null values.
Let me know if you have any issue with it.

Related

How to do a complicated SQLite Join with Count

With SQLite, Given the tables below
_id Name
1 StudentA
2 StudentB
3 StudentC
and
id StudentId Test Score
1 1 A 5
2 1 B 5
3 1 A 6
4 1 B 6
5 2 A 3
6 2 B 3
7 2 A 4
or in SQL Form
BEGIN TRANSACTION;
DROP TABLE IF EXISTS "Results";
CREATE TABLE IF NOT EXISTS "Results" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"StudentId" INTEGER,
"Test" TEXT,
"Score" INTEGER,
FOREIGN KEY("StudentId") REFERENCES "Students"("_id")
);
DROP TABLE IF EXISTS "Students";
CREATE TABLE IF NOT EXISTS "Students" (
"_id" INTEGER PRIMARY KEY AUTOINCREMENT,
"Name" TEXT NOT NULL
);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (1,1,'A',5);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (2,1,'B',5);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (3,1,'A',6);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (4,1,'B',6);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (5,2,'A',3);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (6,2,'B',3);
INSERT INTO "Results" ("id","StudentId","Test","Score") VALUES (7,2,'A',4);
INSERT INTO "Students" ("_id","Name") VALUES (1,'StudentA');
INSERT INTO "Students" ("_id","Name") VALUES (2,'StudentB');
INSERT INTO "Students" ("_id","Name") VALUES (3,'StudentC');
COMMIT;
I would like to show which students have missed which tests and by how many times
The SQL query below gets me close but not exactly what I need
SELECT s.Name, r.Test, COUNT(r.Test) AS Count
FROM Students s
LEFT OUTER JOIN Results r ON s._id = r.StudentId
GROUP BY s._id, r.Test
Gives me the results table:-
Name Test Count
StudentA A 2
StudentA B 2
StudentB A 2
StudentB B 1
StudentC NULL 0
BUT I would like the table as shown below:-
Name Test Count
StudentA A 2
StudentA B 2
StudentB A 2
StudentB B 1
StudentC A 0
StudentC B 0
Is there any way to do this with SQLite?
Cross join the table Students with the distinct Tests and then left join to the table Results:
WITH cte AS (
SELECT *
FROM Students
CROSS JOIN (SELECT DISTINCT Test FROM Results)
)
SELECT c.Name, c.Test, COUNT(r.Test) AS Count
FROM cte c
LEFT OUTER JOIN Results r ON c._id = r.StudentId AND c.Test = r.Test
GROUP BY c.Name, c.Test
See the demo.
Or without the CTE:
SELECT s.Name, t.Test, COUNT(r.Test) AS Count
FROM Students s
CROSS JOIN (SELECT DISTINCT Test FROM Results) t
LEFT OUTER JOIN Results r ON s._id = r.StudentId AND t.Test = r.Test
GROUP BY s.Name, t.Test
See the demo.
Results:
| Name | Test | Count |
| -------- | ---- | ----- |
| StudentA | A | 2 |
| StudentA | B | 2 |
| StudentB | A | 2 |
| StudentB | B | 1 |
| StudentC | A | 0 |
| StudentC | B | 0 |

SQL Query: How to count occurrence of a specific value in a column without grouping on that column?

I have a table like this:
id | value
1 | a
1 | a
1 | b
1 | c
2 | a
2 | a
2 | a
2 | c
And I want to count(*) by id and then count(value==a) by id, which means this is the desired results:
id | total_counts | a_counts
1 | 4 | 2
2 | 4 | 3
I know how to do it by joining two subqueries, but is there an easier/faster way to do it? Like this pseudo-code:
SELECT id, COUNT(*) AS total_counts, COUNT(value==a) AS a_counts
FROM table
GROUP BY id
Not sure if there is a way to do the COUNT(value==a) part. Please kindly help.
You could use SUM:
SELECT id, COUNT(*) AS total_counts, SUM(value='a') AS a_counts
FROM table
GROUP BY id;
Or if you have SQLite 3.25 you could use windowed version:
SELECT /*DISTINCT*/
id,
COUNT(*) OVER(PARTITION BY id) AS total_counts,
COUNT(*) FILTER (WHERE value = 'a') OVER(PARTITION BY id) AS a_counts
FROM tab

update table in sorted order

I am maintaining table structure like below.
sortid | id | name
1 | 1 | aa
3 | 2 | cc
4 | 3 | cc
2 | 4 | bb
5 | 5 | dd
Where sortid is maintained according to ascending order of name.
Now I want to update name 'dd' to 'aa', such way that sort id is also updated to its correct value.
Update table set name="bb" where name like "dd";
After updating my table should become like below.
sortid | id | name
1 | 1 | aa
4 | 2 | cc
5 | 3 | cc
3 | 4 | bb
2 | 5 | aa
That sortid is the number of rows that would be sorted before this row.
So you can compute it by counting rows:
UPDATE MyTable
SET sortid = (SELECT COUNT(*)
FROM MyTable AS T2
WHERE T2.name < MyTable.name) +
(SELECT COUNT(*)
FROM MyTable AS T2
WHERE T2.name = MyTable.name
AND T2.id <= MyTable.id);
(The second subquery resolves duplicate sortid values that would result from duplicate names.)

How to join these two tables properly?

I have these two tables
customers:
id | name | address
---+---------------------+-------------------------
1 | company 1 | some address information
2 | company 2 | another address
3 | yet another company | no address here
orders:
id | customer_id | date
---+-------------+---------
1 | 2 | 20151209
2 | 2 | 20151211
3 | 3 | 20151210
4 | 1 | 20151223
Now I want to get a resulting table with each customer on the left and the amount of orders within an arbitrary period of time on the right.
For example, given this period to be 20151207 <= date <= 20151211, the resulting table should look like this:
name | orders count
--------------------+-------------
company 1 | 0
company 2 | 2
yet another company | 1
Note: date = 20151207 means the 7th of december 2015.
How to join them?
SELECT c.name, COUNT(CASE WHEN ((o.date BETWEEN 20151207 AND 20151211) OR (o.date ISNULL)) THEN o.customer_id END) AS "Total Sales" FROM customers AS c LEFT JOIN orders o ON c.id == o.customer_id GROUP BY c.name

Query returning incorrect count

I have the following query.
SELECT a.link_field1 AS journo, count(a.link_id) as articles, AVG( b.vote_value ) AS score FROM dan_links a LEFT JOIN dan_votes b ON link_id = vote_link_id WHERE link_field1 <> '' and link_status NOT IN ('discard', 'spam', 'page') GROUP BY link_field1 ORDER BY link_field1, link_id
This query is returning a count of 3 for the first item in the list. What should be returned is
Journo | count | score
John S | 2 | 6.00
Joe B | 1 | 4
However for the first one John S, it returns a count of 3.
If I directly query
select * from dan_links where link_field1 = 'John S'
I get 2 records return as I would expect. I can't for the life of me figure out why the count is wrong, unless for some reason it is counting the records from the dan_vote table
How can I get the correct count, or is my query completely wrong?
EDIT: Contents of the tables
dan_links
link_id | link_field1 | link | source | link_status
1 | John S | http://test.com | test.com | approved
2 | John S | http://google.com | google | approved
3 | Joe B | http://facebook.com | facebook | approved
dan_votes
vote_id | link_id | vote_value
1 | 1 | 5
2 | 1 | 8
3 | 2 | 4
4 | 3 | 1
EDIT: it looks like it is counting the rows in the votes table for some reason
When you are doing a left outer join with the condition link_id = vote_link_id for every matching record one row is created, some thing like
link_id | link_field1 | link | source | link_status|vote_id|vote_value
1 | John S | http://test.com | test.com | approved|1|5
1 | John S | http://test.com | test.com | approved|2|8
2 | John S | http://google.com | google | approved|3|4
3 | Joe B | http://facebook.com | facebook | approved|4|1
Now when you do group by on link_field1, you get count as 3 for John S
Nested query might work
SELECT journo,count(linkid) as articles,AVG(score) FROM
(SELECT a.link_field1 AS journo, AVG( b.vote_value ) AS score, a.link_id as linkid
FROM dan_links a
LEFT JOIN dan_votes b
ON link_id = vote_link_id
WHERE link_field1 <> ''
and link_status NOT IN ('discard', 'spam', 'page')
GROUP BY link_id
ORDER BY link_field1, link_id) GROUP BY journo
The above query will give incorrect average as ((n1+n2)/2+n3)/2 != (n1+n2+n3)/3, so use the below query
SELECT journo,count(linkid) as articles, SUM(vote_sum)/SUM(count(linkid))
FROM
(SELECT a.link_field1 AS journo, SUM( b.vote_value ) AS vote_sum, a.link_id as linkid, count(a.link_id) as count_on_id
FROM dan_links a
LEFT JOIN dan_votes b
ON link_id = vote_link_id
WHERE link_field1 <> ''
and link_status NOT IN ('discard', 'spam', 'page')
GROUP BY link_id
ORDER BY link_field1, link_id) GROUP BY journo
Hope this helps.

Resources