Return result of several set operations on subqueries - mysql

I am using MySql and running the following queries.
(select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from db.CRE
where CONTENT = '183' and LEVEL = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from db.CRE
where CONTENT = '182' and LEVEL = '99')
(select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from db.CRE
where CONTENT = '183' and LEVEL = '99'
INTERSECT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from db.CRE
where CONTENT = '182' and LEVEL = '99')
(select CONCAT(RESOURCE, " AMB:", AMB) AS REC_2 from db.CRE
where CONTENT = '182' and LEVEL = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_2 from db.CRE
where CONTENT = '183' and LEVEL = '99')
The subqueries are always the same but the set operation changes. All of these queries work on their own. The first tells me the feature unique to subquery a the second what both share and the third what is unique to subquery b. The issue is that I would like to get all three of these returned at the same time. One column being REC_1 another REC_SAME another REC_2.
I have tried using UNIONS to join the but this fails if any of them are null. I have also tried using select without a from but it also didn't work.
The results i would expect to be with the following structure.In which rec1 would contain the results of the first query , rec_same of the intersect query and rec_2 of the last query.
Rec1|Rec_same|Rec2

AS MySQL doesn't support FULL OUTER JOIN you have to build it by hand
SELECT
REC_1,REC_SAME,REC_2
FROM
(SELECT
REC_1,REC_SAME
FROM
((select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from CRE
where CONTENT = '183' and `LEVEL` = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from CRE
where CONTENT = '182' and `LEVEL` = '99')) a1
LEFT JOIN
((select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from CRE
where CONTENT = '183' and `LEVEL` = '99'
INTERSECT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from CRE
where CONTENT = '182' and `LEVEL` = '99')) a2 ON a1.REC_1 = a2.REC_SAME
UNION
SELECT
REC_1,REC_SAME
FROM
(((select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from CRE
where CONTENT = '183' and `LEVEL` = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from CRE
where CONTENT = '182' and `LEVEL` = '99')) a1
RIGHT JOIN
((select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from CRE
where CONTENT = '183' and `LEVEL` = '99'
INTERSECT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from CRE
where CONTENT = '182' and `LEVEL` = '99')) a2 ON a1.REC_1 = a2.REC_SAME) ) b1
LEFT JOIN
(select CONCAT(RESOURCE, " AMB:", AMB) AS REC_2 from CRE
where CONTENT = '182' and LEVEL = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_2 from CRE
where CONTENT = '183' and LEVEL = '99') b2 ON b1.REC_1 = b2.REC_2 OR b1.REC_SAME = b2.REC_2
UNION
SELECT
REC_1,REC_SAME,REC_2
FROM
(SELECT
REC_1,REC_SAME
FROM
((select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from CRE
where CONTENT = '183' and `LEVEL` = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from CRE
where CONTENT = '182' and `LEVEL` = '99')) a1
LEFT JOIN
((select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from CRE
where CONTENT = '183' and `LEVEL` = '99'
INTERSECT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from CRE
where CONTENT = '182' and `LEVEL` = '99')) a2 ON a1.REC_1 = a2.REC_SAME
UNION
SELECT
REC_1,REC_SAME
FROM
(((select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from CRE
where CONTENT = '183' and `LEVEL` = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_1 from CRE
where CONTENT = '182' and `LEVEL` = '99')) a1
RIGHT JOIN
((select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from CRE
where CONTENT = '183' and `LEVEL` = '99'
INTERSECT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_SAME from CRE
where CONTENT = '182' and `LEVEL` = '99')) a2 ON a1.REC_1 = a2.REC_SAME) ) b1
RIGHT JOIN
(select CONCAT(RESOURCE, " AMB:", AMB) AS REC_2 from CRE
where CONTENT = '182' and LEVEL = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC_2 from CRE
where CONTENT = '183' and LEVEL = '99') b2 ON b1.REC_1 = b2.REC_2 OR b1.REC_SAME = b2.REC_2

You can add rec_type('rec_1', 'rec_same','rec_2') columns in all 3 subqueries, and then perform a union. At the end, use group by and sum function to exact which rec is rec_1/rec_same/rec_2. See the example query:
WITH rec_1 as(
(select CONCAT(RESOURCE, " AMB:", AMB) AS REC, 'rec_1' as rec_type from db.CRE
where CONTENT = '183' and LEVEL = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC, 'rec_1' as rec_type from db.CRE
where CONTENT = '182' and LEVEL = '99')
),
rec_same AS (
(select CONCAT(RESOURCE, " AMB:", AMB) AS REC, 'rec_same' as rec_type from db.CRE
where CONTENT = '183' and LEVEL = '99'
INTERSECT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC,'rec_same' as rec_type from db.CRE
where CONTENT = '182' and LEVEL = '99')
),
rec_2 AS (
(select CONCAT(RESOURCE, " AMB:", AMB) AS REC,'rec_2' as rec_type from db.CRE
where CONTENT = '182' and LEVEL = '99'
EXCEPT
select CONCAT(RESOURCE, " AMB:", AMB) AS REC, 'rec_2' as rec_type from db.CRE
where CONTENT = '183' and LEVEL = '99')
),
rec_union AS(
select
REC, rec_type
FROM
rec_1
UNION
select
REC, rec_type
FROM
rec_same
UNION
select
REC, rec_type
FROM
rec_2
)
select
rec,
sum(rec_type = 'rec_1') as is_rec_1,
sum(rec_type = 'rec_same') as is_rec_same,
sum(rec_type = 'rec_2') as is_rec_2
from
rec_union
group by rec

You can do:
with
a as (select concat(resource, " AMB:", amb) as c from cre where content = '183' and level = '99'),
b as (select concat(resource, " AMB:", amb) as c from cre where content = '182' and level = '99')
select *
from (
select 'same' as type, a.c from a join b on b.c = a.c
union all select 'rec1' as type, a.c from a left join b on b.c = a.c where b.c is null
union all select 'rec2' as type, b.c from b left join a on b.c = a.c where a.c is null
) x;
Result:
type c
----- -------
same 3 AMB:4
rec1 5 AMB:6
rec2 1 AMB:2
See running example at db<>fiddle.

Related

syntax error (missing operator) in query expression sri.invoiceNo = sri.invoiceNo INNER JOIN Staff s oN s.Staffid = sr.userld

"SELECT SalesReturnId, ReturnDate, sr.InvoiceNo, (lastname & ', ' & firstname & ', ' & MI) as StaffName, TotalAmount, SUM(sri.Quantity) as TotalQuantity FROM SalesReturn sr INNER JOIN SalesReturnItem sri ON sr.InvoiceNo = sri.InvoiceNo INNER JOIN Staff s ON s.StaffId = sr.userID WHERE ReturnDate BETWEEN '" + startDate.ToString("yyyy-MM-dd") + "' AND '" + endDate.ToString("yyyy-MM-dd") + "' AND sr.InvoiceNo LIKE '%" + txtName.Text + "%' GROUP BY sr.InvoiceNo ORDER BY ReturnDate, sr.InvoiceNo DESC";
When I run that query I keep getting this error:
syntax error (missing operator) in query expression sri.invoiceNo =
sri.invoiceNo INNER JOIN Staff s oN s.Staffid = sr.userld
In Access you need parentheses when you have more than one join:
SELECT SalesReturnId, ReturnDate, sr.InvoiceNo,
(lastname & ', ' & firstname & ', ' & MI) as StaffName,
TotalAmount, SUM(sri.Quantity) as TotalQuantity
FROM (SalesReturn sr
INNER JOIN SalesReturnItem sri ON sr.InvoiceNo = sri.InvoiceNo )
INNER JOIN Staff s ON s.StaffId = sr.userID
WHERE ReturnDate BETWEEN '" + startDate.ToString("yyyy-MM-dd") + "' AND '" + endDate.ToString("yyyy-MM-dd") + "'
AND sr.InvoiceNo LIKE '%" + txtName.Text + "%'
GROUP BY sr.InvoiceNo
ORDER BY ReturnDate, sr.InvoiceNo DESC;

union with group by mysql

Hi I have a query as follows but group by is not working.
SELECT messages.thread_id,messages.subject,messages.message_id,messages.status,messages.attachment,login.name, DATE_FORMAT( messages.date, '%D-%b-%Y' ) as date from messages inner join login on messages.receiver = login.id where (messages.sender = '" . mysql_real_escape_string(trim($_SESSION['login_id'])) . "' and messages.status = 'trash' )
UNION SELECT messages.thread_id,messages.subject,messages.message_id,messages.status,messages.attachment,login.name, DATE_FORMAT( messages.date, '%D-%b-%Y' ) as date from messages inner join login on messages.sender = login.id where (messages.receiver = '" . mysql_real_escape_string(trim($_SESSION['login_id'])) . "' and messages.status = 'trash') GROUP BY messages.thread_id
Wrap your query to an outer query so that it can group the combined results from both the queries.
SELECT z.*
FROM
(
SELECT messages.thread_id, messages.subject, messages.message_id, messages.status,
messages.attachment, login.name, DATE_FORMAT( messages.date, '%D-%b-%Y' ) as date
FROM messages
INNER JOIN login ON messages.receiver = login.id
WHERE messages.sender = '" . mysql_real_escape_string(trim($_SESSION['login_id'])) . "'
AND messages.status = 'trash'
UNION
SELECT messages.thread_id, messages.subject, messages.message_id, messages.status,
messages.attachment, login.name, DATE_FORMAT( messages.date, '%D-%b-%Y' ) as date
FROM messages
INNER JOIN login ON messages.sender = login.id
WHERE messages.receiver = '" . mysql_real_escape_string(trim($_SESSION['login_id'])) . "'
AND messages.status = 'trash'
) AS z
GROUP BY z.thread_id
You have to put brackets around the union select, give it an alias and select from it:
SELECT A.* FROM
(messages.thread_id,messages.subject,messages.message_id,messages.status,mess
ages.attachment,login.name, DATE_FORMAT( messages.date, '%D-%b-%Y' ) as
date from messages inner join login on messages.receiver = login.id
where (messages.sender = '" .
mysql_real_escape_string(trim($_SESSION['login_id'])) . "' and
messages.status = 'trash' )
UNION SELECT
messages.thread_id,messages.subject,messages.message_id,messages.status,messa
ges.attachment,login.name, DATE_FORMAT( messages.date, '%D-%b-%Y' ) as
date from messages inner join login on messages.sender = login.id where
(messages.receiver = '" .
mysql_real_escape_string(trim($_SESSION['login_id'])) . "' and
messages.status = 'trash')) AS A
GROUP BY A.thread_id

How to make MySQL code shorter?

Im trying to do a date filter for my report generate form. I have a DateTimePicker with checkbox in this form, If checkbox checked the query will add a WHERE clause.
Currently Im doing this way:-
If DateTimePicker1.Checked Then
query = "SELECT payment_type, sales_payment_dtl.payment_amt, payment_remark, sales_payment_dtl.created_date, sales.inv_no
FROM sales_payment_dtl
INNER JOIN sales_payment
ON sales_payment_dtl.payment_id = sales_payment.payment_id
INNER JOIN sales
ON sales_payment.sales_id = sales.sales_id
WHERE sales_payment_dtl.created_date = '"& DateTimePicker.Text &"'"
Else
query = "SELECT payment_type, sales_payment_dtl.payment_amt, payment_remark, sales_payment_dtl.created_date, sales.inv_no
FROM sales_payment_dtl
INNER JOIN sales_payment
ON sales_payment_dtl.payment_id = sales_payment.payment_id
INNER JOIN sales
ON sales_payment.sales_id = sales.sales_id"
End If
Is it possible to make the code shorter? Because I need to add somemore filter in future, then the code will become very long, Maybe something like this?
query = "SELECT payment_type, sales_payment_dtl.payment_amt, payment_remark, sales_payment_dtl.created_date, sales.inv_no
FROM sales_payment_dtl
INNER JOIN sales_payment
ON sales_payment_dtl.payment_id = sales_payment.payment_id
INNER JOIN sales
ON sales_payment.sales_id = sales.sales_id
IF '"& DateTimePicker.Checked = True &"' THEN
WHERE sales_payment_dtl.created_date = '"& DateTimePicker.Text &"'
ELSE
do nothing"
Simple logic.
query = "SELECT payment_type, sales_payment_dtl.payment_amt, payment_remark, sales_payment_dtl.created_date, sales.inv_no " & _
"FROM(sales_payment_dtl) " & _
"INNER JOIN sales_payment " & _
"ON sales_payment_dtl.payment_id = sales_payment.payment_id " & _
"INNER JOIN sales " & _
"ON sales_payment.sales_id = sales.sales_id"
If DateTimePicker1.Checked Then
query &= " WHERE sales_payment_dtl.created_date = '" & DateTimePicker.Text & "'"
End If

union not working empty results

I tried using inner join and union not working
sql="SELECT * FROM " +
"(SELECT order_id, order_date, order_status, order_value, order_sapId, order_from, order_clientAcct, order_error, order_visitId, order_cancelled, distributor_name " +
" FROM `orders` " +
" JOIN visits on visit_id = order_visitId " +
" JOIN Name ON user_id = visit_userId " +
" JOIN distributor ON distributor_id = visit_outlet_id " +
" WHERE order_from = 'CSFA' AND user_id = '"+ App.getUserData("user_id")+"' " +
")" +
" JOIN " +
"(SELECT order_id, order_date, order_status, order_value, order_sapId, order_from, order_clientAcct, order_error, order_visitId, order_cancelled, distributor_name " +
" FROM `orders` " +
" JOIN distributor ON order_clientAcct = distributor_accountName " +
" JOIN user ON salesEmpNo = user_sapId " +
" WHERE order_from = 'u' AND user_id = '"+ App.getUserData("user_id")+"' " +
") " +
"" +
"ORDER BY order_id DESC LIMIT 100" +
"";
I need a way to join the two results
1. tried inner join
2.tried union
E/SQLiteLog: (1) near "(": syntax error
11-24 19:53:01.017 13531-13531/E/AndroidRuntime: FATAL EXCEPTION: main
Process: , PID: 13531
android.database.sqlite.SQLiteException: near "(": syntax error (code 1): , while compiling: SELECT * FROM (SELECT order_id, order_date, order_status, order_value, order_sapId, order_from, order_clientAcct, order_error, order_visitId, order_cancelled, distributor_name FROM orders JOIN visits on visit_id = order_visitId JOIN Name ON user_id = visit_userId JOIN distributor ON distributor_id = visit_outlet_id WHERE order_from = 'CSFA' AND user_id = '75' ) UNION (SELECT order_id, order_date, order_status, order_value, order_sapId, order_from, order_clientAcct, order_error, order_visitId, order_cancelled, distributor_name FROM orders JOIN distributor ON order_clientAcct = distributor_accountName JOIN user ON salesEmpNo = user_sapId WHERE order_from = 'u' AND user_id = '75' ) ORDER BY order_id DESC LIMIT 100
That is the error log
after days of research finally got an answer .Used LEFT JOIN and OR to get data from table only where they match.
sql="" +
"SELECT DISTINCT order_id, order_date, order_status, order_value, order_sapId, order_from, order_clientAcct, order_error, order_visitId, order_cancelled, distributor_name " +
" FROM `orders` " +
" LEFT JOIN visits,user,distributor ON (visit_id = order_visitId AND user_id = visit_userId AND distributor_id = visit_outlet_id AND order_from = 'CSFA' AND user_id = '"+ App.getUserData("user_id")+"') OR " +
" " +
" ( order_clientAcct = distributor_accountName AND salesEmpNo = user_sapId AND order_from = 'SAP' AND user_id = '"+ App.getUserData("user_id")+"' )" +
" " +
"ORDER BY order_id DESC LIMIT 100" +
"";

Multiple Count() in Database

I'm making a survey-applican with winforms and VB. This is the SQL I got so far to show statistics:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID)
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
This returns each alternatives for a question, and how many answered them. Is there a way I can count how many answered in total with the same SQL-query?
Tables involved are:
_______________ _______________ ___________ _______________
|_tblUsers____| |_tblAnswers___| |_tblAlt__| |_tblQuestion_|
| userID | | answerAltID | | altID | | questID |
| username | | userID | | altText | | questText |
|_____________| |______________| |_questID_| |_____________|
Any help would be appreciated!
This is what I used in the end:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID),
(SELECT COUNT(answerID) FROM tblAnswers, tblAlt
WHERE tblAnswers.answerAltID = tblAlt.altID
AND tblAlt.questID = " & CInt(questionID) & ") as total_count
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
Use ROLLUP:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID)
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText WITH ROLLUP;
If you want one-time computation(to make query efficient), use CROSS JOIN. Don't worry, this CROSS JOIN won't yield cartesian product, it's only one row. This might be faster than subquery approach:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID), x.total_count
FROM tblAlt
cross join (SELECT COUNT(answerID) as total_count FROM tblAnswers) as x
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
Or use MySqlism, might be faster:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID), #total_count as total_count
FROM tblAlt
cross join (SELECT #total_count := COUNT(answerID) FROM tblAnswers) as x
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
Or you can use multi-statements. Note, SET statements doesn't appear on ADO.NET's DataReader or DataTable. ADO.NET can still get the results from your actual query. This has a certainty to be faster among all approaches:
SET #total_count := (SELECT COUNT(answerID) FROM tblAnswers);
SELECT
tblAlt.altText,
Count(tblAnswers.answerID), #total_count as total_count
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
you can use an subquery to do this, something like:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID),
(SELECT COUNT(answerID) FROM tblAnswers) as total_count
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
Some Resources:
http://beginner-sql-tutorial.com/sql-subquery.htm
http://www.1keydata.com/sql/sql-subquery.html