Using MySQL.
Below is my table structure.
batch_admissions
------------------------+
batchId | studentId |
----------------------- +
1 | 1 |
1 | 2 |
1 | 3 |
2 | 1 |
2 | 2 |
------------------------+
attendance_master
----------------------------+
attendance | studentId |
----------------------------+
P | 1 |
P | 2 |
P | 3 |
----------------------------+
desire result if batchId=2 as below as attendance_master only contain record of batchId=1
----------------------------+
attendance | studentId |
----------------------------+
| 1 |
| 2 |
----------------------------+
But currently I am getting all record back from attendance_master irrespective of change in batchId.
What wrong in my query? I think left join should do the job. but not working
SELECT
a.attendanceId,
a.attendanceDate,
a.attendance,
a.Remarks,
CONCAT(b.studentFirstName, ' ', COALESCE(b.studentMiddleName,'') , ' ', b.studentLastName) as studentName ,
c.classRollNum,
SUBSTRING_INDEX(SUBSTRING_INDEX( a.attendanceDate , '-', 3 ),'-',-1) AS attDay,
CASE WHEN DAYNAME(a.attendanceDate) = 'Monday' THEN 'Mon'
WHEN DAYNAME(a.attendanceDate) = 'Tuesday' THEN 'Tue'
WHEN DAYNAME(a.attendanceDate) = 'Wednesday' THEN 'Wed'
WHEN DAYNAME(a.attendanceDate) = 'Thursday' THEN 'Thu'
WHEN DAYNAME(a.attendanceDate) = 'Friday' THEN 'Fri'
WHEN DAYNAME(a.attendanceDate) = 'Saturday' THEN 'Sat'
WHEN DAYNAME(a.attendanceDate) = 'Sunday' THEN 'Sun'
END as attDayName
,CONCAT(SUBSTRING_INDEX(SUBSTRING_INDEX( a.attendanceDate , '-', 3 ),'-',-1),'.',c.classRollNum) as Idx
FROM attendance_master a
LEFT JOIN student_master b ON a.studentId = b.studentId
LEFT JOIN batch_admissions c ON c.studentId = a.studentId AND c.batchId=1
WHERE a.attendanceDate BETWEEN '2016-03-01' AND '2016-03-31'
ORDER BY c.classRollNum ASC
-------------
Basically I trying to avoid triggering two queries and want result in single query.
batch_admissions table holds series of batch with N numbers student in it.
attendance_master table holds attendance of students for all batch.
On web page I am displaying table grid report, per batch wise.
What I am trying to achieve,
case 1 : when attendance_master NOT contain attendance for batchId for specific period. Still want list of student for that batch
-------------------------------------------------------
BatchId |studentId | Mon | Tue | Wed | Thus |
------------------------------------------------------
1 | 11 | | | | |
1 | 12 | | | | |
.. | .. | | | | |
Case 2: when attendance_master contain attendance for batchId for specific period.
-------------------------------------------------------
BatchId |studentId | Mon | Tue | Wed | Thus |
------------------------------------------------------
2 | 1 | P | P | P | P |
2 | 2 | P | A | P | P |
.. | .. | P | P | P | P |
Alternate I can trigger two queries to achieve this logically. One for get of student for batch, and then getting attendance detail for all those student.
ok... so return all records from batch admissions and the related student_master data (which there will always be records) and the associated attendance master data...
FROM batch_admissions c
INNER JOIN student_master b
ON a.studentId = c.studentId
LEFT JOIN attendance_master a
ON c.studentId = a.studentId
and a.attendanceDate BETWEEN '2016-03-01' AND '2016-03-31'
WHERE c.batchId=1
ORDER BY c.classRollNum ASC
Related
We have 3 tables :
donations
purposes
expenses
Donations :
+--------+------+
| do_id | name |
+--------+------+
| 1 | A |
| 2 | B |
| 3 | A |
| 4 | D |
| 5 | B |
| 6 | B |
| 7 | A |
| 8 | B |
+--------+----- +
purposes:
+-------+-------+--------+
| pu_id | do_id | purpose|
+-------+-------+--------+
| 1 | 2 | abc |
| 2 | 2 | def |
| 3 | 2 | gih |
| 4 | 3 | jkl |
+-------+-------+--------+
expense :
+-------+-------+---------+
| ex_id | do_id | expense |
+-------+-------+---------+
| 1 | 2 | abc |
| 2 | 2 | def |
| 3 | 2 | gih |
| 4 | 3 | jkl |
+-------+-------+---------+
Now i want to make query to get all donations for donor B and join purposes table to get all purposes related to every donation_id then join expenses table to get all expenses related to donation_id and put all of that in every loop independently something like that
Row number 0
donation_id = 1
array(purposes)
array(expenses)
Row number 1
donation_id = 2
array(purposes)
array(expenses)
Row number 2
donation_id = 3
array(purposes)
array(expenses)
Row number 3
donation_id = 4
array(purposes)
array(expenses)
This is my try :
SELECT *, (
SELECT *
FROM `donation_purposes`
WHERE `donation_purposes`.`dopu_donation_id` = 4
) AS `purposes`
FROM `donations`
WHERE `donation_id` = '4'
thanks in advance
You should be able to solive this with an aggregate query using MySQL aggregate function JSON_ARRAYAGG(), like :
SELECT
d.do_id,
JSON_ARRAYAGG(p.purpose) purposes,
JSON_ARRAYAGG(e.expense) expenses
FROM donations d
INNER JOIN purposes p ON p.do_id = d.do_id
INNER JOIN expense e ON e.do_id = d.do_id
GROUP BY d.do_id
I you want to avoid duplicate values in the array, and as JSON_ARRAYAGG() (sadly) does not support the DISTINCT option, you can move aggregation to subqueries, like :
SELECT
d.do_id,
p.agg purpose,
e.agg expenses
FROM donations d
INNER JOIN (
SELECT do_id, JSON_ARRAYAGG(purpose) agg FROM purposes GROUP BY do_id
) p ON p.do_id = d.do_id
INNER JOIN (
SELECT do_id, JSON_ARRAYAGG(expense) agg FROM expense GROUP BY do_id
) e ON e.do_id = d.do_id
This demo on DB Fiddle returns :
| do_id | purpose | expenses |
| ----- | --------------------- | --------------------- |
| 2 | ["abc", "def", "gih"] | ["abc", "def", "gih"] |
| 3 | ["jkl"] | ["jkl"] |
1st Select Query Purposes
SELECT purposes.* FROM purposes
LEFT JOIN donations
ON purposes.do_id = donations.do_id
WHERE donations.do_id = '2' //This depends on the id of the donation
ORDER BY purposes.do_id ASC
2nd Select Query Expenses
SELECT expense.* FROM expense
LEFT JOIN donations
ON expense.do_id = donations.do_id
WHERE donations.do_id = '2' //This depends on the id of the donation
ORDER BY expense.ex_id ASC
All queries generated are from the table structure you've provided, but your question is quite vague!!
Table:
person | borrow_date | is_borrowed | SN | date | id
1 | 2019-01-10...| 1 | 20 |2019-01-10...| 6
3 | 2019-01-09...| 3 | 10 |2019-01-09...| 5
1 | 2019-01-08...| 1 | 10 |2019-01-08...| 4
2 | 2019-01-08...| 1 | 10 |2019-01-08...| 3
1 | NULL | 2 | 20 |2019-01-07...| 2
1 | NULL | 2 | 10 |2019-01-07...| 1
My wanted output is to select newest rows where "is_borrowed" equals 1 and grouped by SN, so that when the query is executed with person=2 or person=3 then it would retrieve empty set. Whereas for person=1 it would give back two rows.
Wanted output (where person=1):
person | borrow_date | is_borrowed | SN | date |id
1 | 2019-01-10...| 1 | 20 | 2019-01-10...|6
1 | 2019-01-08...| 1 | 10 | 2019-01-08...|4
Wanted output (where person=2):
EMPTY SET
Wanted output (where person=3):
EMPTY SET
This is my current query and it sadly doesn't work.
SELECT a.SN, a.is_borrowed,a.max(date) as date, a.person
FROM table a
INNER JOIN (SELECT SN, MAX(date) as date, osoba from table where person like
"2" group by SN) as b
ON a.SN=b.SN and a.date=b.date
WHERE a.person like "2" and a.is_borrowed=1
If I correctly understood you from the question and the comment you made under it, here's one way to do it without specifying the person:
select *
from TableName as p
inner join (select max(borrow_date) as borrow_date,
SN
FROM TableName
where is_borrowed = 1
group by SN) as p2
on p.borrow_date = p2.borrow_date and p.SN = p2.SN
This should give you the result you're looking for. Here's a demo.
Note that I had to change the borrowed_date values in the table since yours contain hours and minutes while I didn't add those.
You can always specify it for each person by adding a where clause after the join.
select p.person,
p.borrow_date,
p.is_borrowed,
p.SN,
p.date,
p.id
from TableName as p
inner join (select max(borrow_date) as borrow_date,
SN
FROM TableName
where is_borrowed = 1
group by SN) as p2
on p.borrow_date = p2.borrow_date and p.SN = p2.SN
where p.person = '1'
Output:
person | borrow_date | is_borrowed | SN | date | id
1 | 2019-01-10 | 1 | 20 | 2019-01-10 | 6
1 | 2019-01-08 | 1 | 10 | 2019-01-08 | 4
While where p.person = '2' and where p.person = '3' will return empty sets.
Say we have the following tables, employee and payroll_slip:
Table: employee
id_employee | name_employee |
============|===============|
1 | john |
2 | doe |
3 | alex |
Table: payroll_slip
id_slip | id_employee | month_slip | year_slip |
========|=============|============|===========|
1 | 1 | 01 | 2016 |
2 | 2 | 01 | 2016 |
3 | 1 | 02 | 2016 |
4 | 2 | 02 | 2016 |
5 | 1 | 03 | 2016 |
6 | 3 | 03 | 2016 |
And we want to get the following result where month_slip = '03' AND year_slip = '2016'
id_employee | month_slip | year_slip | status_slip
============|============|===========|============
1 | 03 | 2016 | paid
2 | 03 | 2016 | unpaid
3 | 03 | 2016 | paid
I tried this query:
SELECT
a.id_employee,
payroll_slip.month_slip,
payroll_slip.year_slip,
IF(a.id_employee=payroll_slip.id_employee, 'paid', 'unpaid') AS status_slip
FROM (
SELECT id_employee FROM employee
UNION
SELECT id_employee FROM payroll_slip
) a
LEFT OUTER JOIN payroll_slip ON a.id_employee = payroll_slip.id_employee
LEFT OUTER JOIN employee ON a.id_employee = employee.id_employee
WHERE payroll_slip.month_slip = '03' AND payroll_slip.year_slip = '2016'
Any suggestion for this?
Try having a cross join:
SELECT X.id_employee, X.month_slip, X.year_slip
, CASE WHEN Y.id_employee IS NULL THEN 'Unpaid' ELSE 'Paid' END AS status_slip
FROM (
SELECT A.id_employee, B.month_slip, B.year_slip
from employee A
cross join (
select '03' AS month_slip, '2016' AS year_slip
) B
) X
LEFT JOIN payroll_slip Y
ON X.id_employee = Y.id_employee
AND X.month_slip = Y.month_slip
AND X.year_slip = Y.year_slip
Try this query:
SELECT e.id_employee, '03' AS month_slip, '2016' AS year_slip,
CASE WHEN p.id_employee IS NOT NULL THEN 'paid' ELSE 'unpaid' END AS status_slip
FROM employee e LEFT JOIN payroll_slip p
ON e.id_employee = p.id_employee AND p.month_slip = '03' AND p.year_slip = '2016'
The trick here is to move the restrictions on the month_slip and year_slip inside the JOIN condition, rather than in the WHERE clause.
Follow the link below for a running demo:
SQLFiddle
I have 4 tables:
secu_content
| id | created | modified |
| 910 | 26/12/1982 | 28/12/1984 |
| 911 | 24/12/1982 | 25/12/1984 |
secu_data
| element_id | field_id | data |
| 1 | 1 | 25/12/1984 |
| 2 | 1 | 26/12/1984 |
| 3 | 1 | 27/12/1984 |
| 4 | 1 | 25/12/1984 |
| 4 | 2 | google.com |
secu_elements
| id | item_id |
| 1 | 891 |
| 2 | 711 |
| 3 | 204 |
| 4 | 911 |
secu_fields
| id | type |
| 1 | date |
| 2 | input |
Table secu_content, contains many articles, where the id is the article id.
The other 3 tables gives additional information and I want to join them.
I want to get results that includes all secu_content rows and all the columns + calc_date + calc_link
calc_date <- the data column from secu_data where field_id=1 (see secu_fields)
calc_link <- the data column from secu_data where field_id=2 (see secu_fields)
The problem is that I get 2 rows where secu_content id=911 (one row with the correct calc_date and second row with the correct calc_link), and I need one row with both.
This is my SQL:
SELECT a.id
, a.created
, a.modified
, fe.item_id AS calc_date_item_id
, fd.data AS calc_date
, CASE WHEN fd.data IS NOT NULL AND ff.type = "date" THEN fd.data
WHEN a.modified = '0000-00-00 00:00:00' THEN a.created ELSE a.modified
END as calc_date
, CASE WHEN fd.data IS NOT NULL AND ff.type = "input" THEN fd.data
END as calc_link
FROM secu_content AS a
LEFT
JOIN secu_fieldsandfilters_elements AS fe
ON fe.item_id = a.id
AND fe.content_type_id=1
LEFT
JOIN secu_fieldsandfilters_data AS fd
ON fd.element_id = fe.id
LEFT
JOIN secu_fieldsandfilters_fields as ff
ON ff.id = fd.field_id
ORDER BY a.id DESC;
Thanks in advance
Israel
Fast and dirty solution is to use second join to secu_data like that (simplified, add logic you need)
SELECT id, d1.data as `calc_date`, d2.data as `calc_link`
FROM secu_content
LEFT JOIN secu_data d1 ON secu_content.id = d1.element_id AND field_id = 1
LEFT JOIN secu_data d2 ON secu_content.id = d2.element_id AND field_id = 2
So I've got 2 tables (simplified below)
members documents
------------ ------------------
id | name | registered id | member_id | type | expiry
---------------------- ------------------------------
1 | AAA | 1234567890 1 | 1 | 1 | 1234567890
2 | BBB | 1234567890 2 | 1 | 2 | 1234567891
3 | CCC | 1234567890 3 | 1 | 3 | 1234567892
4 | 2 | 1 | 1234567893
5 | 2 | 2 | 1234567894
6 | 2 | 3 | 1234567890
and I need to display these like this:
member id | name | doc 1 expiry | doc 2 expiry | doc 3 expiry
--------------------------------------------------------------
1 | AAA | 1234567890 | 1234567891 | 1234567892
2 | BBB | 1234567893 | 1234567894 | 1234567895
I've tried querying with multiple outer joins and aliases but it's just repeating the document expiry timestamps. This is what I have so far:
SELECT DISTINCT `members`.`id`, `members`.`name`, `a`.`expiry` AS `expiry1`, `b`.`expiry` AS `expiry2`, `c`.`expiry` AS `expiry3`
FROM `members`
LEFT OUTER JOIN `documents` a ON `a`.`member_id` = `members`.`id`
LEFT OUTER JOIN `documents` b ON `b`.`member_id` = `members`.`id`
LEFT OUTER JOIN `documents` c ON `c`.`member_id` = `members`.`id`
GROUP BY `members`.`id`
People need to be able to search through this, for example to list everyone whose document type 3 has expired.
Try
SELECT
a.id AS 'member id',
a.name
SUM(a.d1exp) AS 'doc 1 expiry',
SUM(a.d2exp) AS 'doc 2 expiry',
SUM(a.d3exp) AS 'doc 3 expiry'
FROM
(
SELECT
aa.id,
aa.name,
COALESCE(d1.expiry, 0) AS d1exp,
COALESCE(d2.expiry, 0) AS d2exp,
COALESCE(d3.expiry, 0) AS d3exp
FROM
members aa
LEFT JOIN
documents d1 ON aa.id = d1.member_id AND d1.type = 1
LEFT JOIN
documents d2 ON aa.id = d2.member_id AND d2.type = 2
LEFT JOIN
documents d3 ON aa.id = d3.member_id AND d3.type = 3
) a
GROUP BY
a.id,
a.name
This is assuming the values in the 'expiry' field are numerical.