I have two tables
Category
CategorySerno | CategoryName
1 One
2 Two
3 Three
Status
StatusSerno | Status
1 Active
2 Pending
Data
CatId |Status | Date
1 1 2014-07-26 11:30:09.693
2 2 2014-07-25 17:30:09.693
1 1 2014-07-25 17:30:09.693
1 2 2014-07-25 17:30:09.693
When I join them I get I need the Joining of the latest Date/
Like
One Active 2014-07-26 11:30:09.693
Two Inactive 2014-07-25 17:30:09.693
Three Null Null
When I am doing a Join and group them It gives me
One Active 2014-07-26 11:30:09.693
One Active 2014-07-26 11:30:09.693
One Active 2014-07-26 11:30:09.693
Two Inactive 2014-07-25 17:30:09.693
Three Null Null
You could use ROW_NUMBER in a CTE:
WITH CTE AS
(
SELECT c.CategoryName,
s.Status,
d.Date,
dateNum = ROW_NUMBER() OVER (PARTITION BY CatId, d.Status
ORDER BY Date DESC)
FROM Category c
LEFT OUTER JOIN Data d
ON c.CategorySerno = d.CatId
LEFT OUTER JOIN Status s
ON d.Status = s.StatusSerno
)
SELECT CategoryName, Status, Date
FROM CTE
WHERE dateNum = 1
Demo-Fiddle
SELECT CategoryName, Status.Status, MAX(Data.Date) FROM Category
LEFT OUTER JOIN Data ON CategorySerno = CatId
LEFT OUTER JOIN Status ON Data.Status = Status.StatusSerno
GROUP BY CategoryName, Status.Status
You prabobly have mismatch between SELECT and GROUP BY columns withch couse duplications
Try this:
SELECT Category.CategoryName, Status.Status, MAX(Data.Date) Data
FROM Data
LEFT JOIN Category ON Category.CategorySerno = Data.CatId
LEFT JOIN Status ON Status.StatusSerno = Data.Status
GROUP BY Category.CategoryName, Status.Status
You don't mention the RDBMS you're working in but you might try starting with something like:
SELECT
c.CategoryName
, s.Status
, d.Date
FROM
Data d
LEFT OUTER JOIN Category c ON d.CatId = c.CategorySerno
LEFT OUTER JOIN Status s ON d.Status = s.StatusSerno
WHERE
d.date=(
SELECT
max(dd.date)
FROM
Data dd
WHERE
d.CatId = dd.CatId
AND
d.Status = dd.Status
) z
To make this more maintainable in the long run, consider using a convention to identify the primary keys in any table, e.g., table_name_id, and use this same convention for foreign keys. Employing this convention address questions like: is a "CategorySerno" a "CatId"?
Related
I am inserting data to an already existing TableA and the following query is a part of a stored procedure. This part of the query inserts values into some columns of TableA. The stored procedure is very lengthy which has several insert statements to fill out the different columns in TableA.
INSERT INTO TableA (ID, Event, Date, Amount, Status_, Country)
(SELECT DISTINCT ID, Event, Date, Amount, c.Status, b.Country
FROM TableA1 a
JOIN TableB1 b ON b.employeeID = a.ID
JOIN TableC1 c ON c.Status = ‘Active’)
Usually, a join condition consists of two columns, for example (a.Status_ = c.Status). But here, it's replaced with a filter condition (JOIN TableC1 c ON c.Status = ‘Active’).
The select query alone executes well and returns results. I'm trying to understand the effect made by this filter condition.
Can you explain, please?
Thanks
It's the same as this...
SELECT DISTINCT
ID, Event, Date, Amount, c.Status, b.Country
FROM
(
TableA1 a
INNER JOIN
TableB1 b
ON b.employeeID = a.ID
)
CROSS JOIN
(
SELECT * FROM TableC1 WHERE Status = 'Active'
)
c
In effect, the INNER JOIN is resolved, and then each row from that is joined to every row from TableC1 WHERE Status = 'Active'
For example
TableA1
ID
Event
Date
Amount
1
e1
2022-01-01
11
2
e2
2022-02-02
22
TableB1
EmployeeID
Country
1
c1
2
c2
TableC1
some_id
Status
1
Sleeping
2
Active
3
Active
4
Sleeping
Would yield...
ID
Event
Date
Amount
Country
Status
(some_id, added by me)
1
e1
2022-01-01
11
c1
Active
2
1
e1
2022-01-01
11
c1
Active
3
2
e2
2022-02-02
22
c2
Active
2
2
e2
2022-02-02
22
c2
Active
3
You probably should have...
INNER JOIN
TableC1 c
ON c.some_id = b.some_other_id
AND c.Status = 'Active'
I have this tables with example data:
Calendar
ID | Date
---+-----------
1 | 2020-01-01
2 | 2020-01-02
3 | 2020-01-03
EmployeeTimeWorked
ID | Date | HoursWorked | UserID
---+------------+--------------+-------
1 | 2020-01-01 | 2 | 2
2 | 2020-01-01 | 4 | 2
I want to make a MS-SQL query that shows days the user have not worked, and how many hours they have left to work (they should work 8 hours per day). All within within a time period, say a week.
The result should look like this:
EmployeeHaveNotWorked
Date | HoursLeftToWork
-----------+----------------
2020-01-01 | 2
Any idea how to make such a MS-SQL Query?
First get all users with all dates. This is done with a cross join. Seeing that you are using a UserID I suppose there is a users table. Otherwise get the users from the EmployeeTimeWorked table.
Then outer join the working times per user and date. This is a simple aggregation query.
Then subtract the worked hours from the required 8 hours.
select
u.userid,
c.date,
8 - coalesce(w.hours_worked, 0) as hours_left_to_work
from users u
cross join calendar c
left outer join
(
select userid, date, sum(hoursworked) as hours_worked
from employeetimeworked
group by userid, date
) w on w.userid = u.userid and w.date = c.date
order by u.userid, c.date;
Use a cross join to generate all possible rows and then filter out the ones that exist:
select u.userid, c.date,
8 - coalesce(sum(HoursWorked), 0) as remaining_time
from calendar c cross join
(select distinct userid from EmployeeTimeWorked) u left join
EmployeeTimeWorked etw
on etw.userid = u.userid and etw.date = c.date
where etw.userid is null
group by u.userid, c.date
having sum(HoursWorked) < 8
This query seem to have done it for me:
select * from (select c.Date, 8 - coalesce(sum(t.durationHours),0) hours_left_to_work
from Calendar c
left join TimeLog t on t.Date = c.Date
where c.date >= '2020-08-01' and c.date <= '2020-08-31'
group by c.Date) as q1
where q1.hours_left_to_work IS NOT NULL
AND q1.hours_left_to_work > 0;
TimeLog = EmployeeTimeWorked
I have two tables, info and transactions.
info looks like this:
customer ID Postcode
1 ABC 123
2 DEF 456
and transactions looks like this:
customer ID day frequency
1 1/1/12 3
1 3/5/12 4
2 4/6/12 2
3 9/9/12 1
I want to know which day has the highest frequency for each postcode.
I know how to reference from two different tables but im not too sure how to reference multiple columns based on their values to other columns.
The output should be something like this:
customer ID postcode day frequency
1 ABC 123 3/5/12 4
2 DEF 456 4/6/12 2
3 GHI 789 9/9/12 1
and so on.
You can filter with a correlated subquery:
select
i.*,
t.day,
t.frequency
from info i
inner join transactions t on t.customerID = i.customerID
where t.frequency = (
select max(t.frequency)
from info i1
inner join transactions t1 on t1.customerID = i1.customerID
where i1.postcode = i.postcode
)
Or, if your RBDMS supports window functions, you can use rank():
select *
from (
select
i.*,
t.day,
t.frequency,
rank() over(partition by i.postcode order by t.frequency desc)
from info i
inner join transactions t on t.customerID = i.customerID
) t
where rn = 1
Master table
SerNo HospitalId CityId
1 1 1
2 1 1
3 2 2
4 3 2
5 1 1
HospitalMaster
HospitalId HospitalName
1 ABC
2 XYZ
CityMaster
CityId City
1 Delhi
2 Bombay
Result
I need something like this
City TotalHospital
Delhi 1
Bombay 2
I tried joining the tables but I keep getting the total rows of the columns and not of the hospitals.
Thank you.
Left join the city master table to a subquery which finds the hospital counts for each city. Note carefully that we only count distinct hospitals, because a hospital city relationship may appear more than once in the master table.
SELECT t1.City, COALESCE(t2.cnt, 0) AS TotalHospital
FROM CityMaster t1
LEFT JOIN
(
SELECT CityId, COUNT(DISTINCT HospitalId) cnt
FROM Master
GROUP BY CityID
) t2
ON t1.CityId = t2.CityId;
Demo
Try this:
SELECT C.City,COUNT(DISTINCT HospitalID)TotalHospital
FROM CityMaster C
JOIN Master_table M ON M.CityId=C.CityId
GROUP BY C.City
You could apply join
select M.City,count(distinct M.HospitalId) from CityMaster C inner join Master M ON C.CityId = M.CityId
group by M.City
You can do it with using JOIN
Just replace #city, #hospital, #table with your table names.
select C.City,T.CityId from #city C,#hosp H,#table T WHERE T.CityId = C.CityId AND T.HospitalId = H.HospitalId Group by C.City,T.CityId
As we need city name along with count, we can get by join city master and master tables.
select max(C.cityname), count(distinct M.HospitalId)
from CityMaster C
inner join Master M
on C.Cityid = M.CityId
group by M.cityid
I have the following tables :
User_Group
id group_id group_type
------------------------
1 100 A
1 100 B
2 101 B
2 102 A
Group_A
id name
---------
100 A
101 B
102 C
Group_B
id name
---------
100 D
101 E
102 F
I want the group names of all users (using array.agg()). We have to get the group name from group A if the user's group type = A and from group B if the user's group type = B. The result should be :
userid groups
--------------
1 A,D
2 E,C
I have created a fiddle for this, and given a solution using union of 2 separate queries. Can it be done without the union, something in which I can decide on which table to pick the group name from with a single join of user_groups, group_A and group_B ?
select ug.id, array_agg(
case ug.group_type
when 'A' then g_a.name
when 'B' then g_b.name
else 'N/A'
end)
from user_groups ug
left outer join group_A g_a on ug.group_id = g_a.id
left outer join group_B g_b on ug.group_id = g_b.id
group by ug.id
SQL Fiddle Example
You can do this without union using left joins (I'd advise using explicit joins anyway since implicit joins are 20 years out of date Aaron Bertrand has written a good blog as to why). The Group_Type can become a join condition meaning the table is only joined when the right group type is found:
SELECT ug.ID, ARRAY_AGG(COALESCE(a.Name, b.Name))
FROM User_Groups ug
LEFT JOIN group_A a
ON a.ID = ug.group_ID
AND ug.Group_Type = 'A'
LEFT JOIN group_B b
ON b.ID = ug.group_ID
AND ug.Group_Type = 'B'
WHERE COALESCE(a.ID, b.ID) IS NOT NULL -- ENSURE AT LEAST ONE GROUP IS MATCHED
GROUP BY ug.ID;
However I would be inclined to use a UNION Still, but move it as follows:
SELECT ug.ID, ARRAY_AGG(Name)
FROM User_Groups ug
INNER JOIN
( SELECT 'A' AS GroupType, ID, Name
FROM Group_A
UNION ALL
SELECT 'B' AS GroupType, ID, Name
FROM Group_B
) G
ON g.GroupType = ug.Group_Type
AND g.ID = ug.Group_ID
GROUP BY ug.ID;
Your Fiddle with my queries added