How to give preference to non-expired posts in union - mysql

The "offer" type expires with 1 or 0, the "Sweep" type expires by expiration date. How can I give them more weight in the query when they re not expired?
The current query (for the search page):
SELECT
'offer' AS type,
id,
expired,
title,
description,
header,
slug,
date_original,
date
FROM cs_offers
WHERE MATCH(title,title,description,keywords,header,country,offer_description) AGAINST ('$search_main' IN BOOLEAN MODE)
UNION
SELECT
'sweep' AS type,
id,
title,
description,
header,
expire_date,
slug,
date_original,
date_original AS date
FROM cs_sweeps
WHERE MATCH(title,title,description,keywords,header,category,location,entry_type,country,w) AGAINST ('$search_main' IN BOOLEAN MODE)
UNION
SELECT
'video' AS type,
id,
id AS id2,
title,
description,
keywords,
slug,
date_original,
date
FROM cs_vlog
WHERE MATCH(title,title,description,keywords,video_description) AGAINST ('$search_main' IN BOOLEAN MODE)
UNION
SELECT
'post' AS type,
id,
id AS id2,
title,
description,
header,
slug,
date_original,
date
FROM cs_blog
WHERE MATCH(title,title,description,keywords,header,body) AGAINST ('$search_main' IN BOOLEAN MODE)
ORDER BY date DESC
In other words, how can make all current posts first in the query?

For every union part create a virtual column expired, then order your whole union by order by expired asc, date desc:
( select ..., expired from offer ... )
union all
( select ..., expire_date < now() as expired from sweep ...)
...
order by expired asc, date desc
Parentheses is important. Also make sure that the number and order of columns in every union part is the same.

Related

order by with union in SQL is not working

Is it possible to order when the data comes from many select and union it together? Such as
In this statement, the vouchers data is not showing in the same sequence as I saved on the database, I also tried it with "ORDER BY v_payments.payment_id ASC" but won't be worked
( SELECT order_id as id, order_date as date, ... , time FROM orders WHERE client_code = '$searchId' AND order_status = 1 AND order_date BETWEEN '$start_date' AND '$end_date' ORDER BY time)
UNION
( SELECT vouchers.voucher_id as id, vouchers.payment_date as date, v_payments.account_name as name, ac_balance as oldBalance, v_payments.debit as debitAmount, v_payments.description as descriptions,
vouchers.v_no as v_no, vouchers.v_type as v_type, v_payments.credit as creditAmount, time, zero as tax, zero as freightAmount FROM vouchers INNER JOIN v_payments
ON vouchers.voucher_id = v_payments.voucher_id WHERE v_payments.client_code = '$searchId' AND voucher_status = 1 AND vouchers.payment_date BETWEEN '$start_date' AND '$end_date' ORDER BY v_payments.payment_id ASC , time )
UNION
( SELECT return_id as id, return_date as date, ... , time FROM w_return WHERE client_code = '$searchId' AND w_return_status = 1 AND return_date BETWEEN '$start_date' AND '$end_date' ORDER BY time)
Wrap the sub-select queries in the union within a SELECT
SELECT id, name
FROM
(
SELECT id, name FROM fruits
UNION
SELECT id, name FROM vegetables
)
foods
ORDER BY name
If you want the order to only apply to one of the sub-selects, use parentheses as you are doing.
Note that depending on your DB, the syntax may differ here. And if that's the case, you may get better help by specifying what DB server (MySQL, SQL Server, etc.) you are using and any error messages that result.
You need to put the ORDER BY at the end of the statement i.e. you are ordering the final resultset after union-ing the 3 intermediate resultsets
To use an ORDER BY or LIMIT clause to sort or limit the entire UNION result, parenthesize the individual SELECT statements and place the ORDER BY or LIMIT after the last one. See link below:
ORDER BY and LIMIT in Unions
(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;

mysqli UNION get data in correct column name

I want to get data from database with UNION , I defined link as newslink, and pic as articlepic but it show articlepic data under newslink column, how can I fix this?
SELECT * FROM
((SELECT date, link as newslink FROM news ORDER BY id DESC)
UNION
(SELECT date, pic as articlepic FROM article ORDER BY id DESC)) as x
ORDER BY date DESC LIMIT 6
Sample Data
I want to get articlepic data under articlepic column, and newslink under newslink column
if you values in different column you must add null value in the select for not corresponding columns
SELECT * FROM
((SELECT date, link as newslink, null as articlepic
FROM news ORDER BY id DESC)
UNION
(SELECT date, null, pic
FROM article ORDER BY id DESC)) as x
ORDER BY date DESC LIMIT 6
You are not able to get the different name of the column when using union in the query
SELECT * FROM
(
(
SELECT
DATE,
link AS newslink,
'-' As articlepic
FROM news ORDER BY id DESC
) UNION (
SELECT
DATE,
'-' As newslink,
pic AS articlepic
FROM article ORDER BY id DESC
)
) AS X
ORDER BY DATE DESC LIMIT 6

order by unselected column with union

Hey i have a query ordered by date, and i want in case the date is identical to order by time added to maintain stable results.
I have the following query :
(
SELECT 'album' AS RowType, id, DATE, title, time_added
FROM albums
WHERE is_temp =0
AND subject_id = '3'
)
UNION ALL (
SELECT 'video' AS RowType, id, DATE, title, time_added
FROM videos
WHERE is_temp =0
AND subject_id = '3'
)
UNION ALL (
SELECT 'story' AS RowType, id, DATE, title, time_added
FROM stories
WHERE is_temp =0
AND subject_id = '3'
)
ORDER BY DATE, time_added
Which works perfectly but i don't want to select the time_added column as i don't need it in my result set.
Can i somehow achive this? if i remove the time_added the query won't run.
I have found the following :
The ORDER BY clause causes the output rows to be sorted.
The argument to ORDER BY is a list of expressions that are used as the
key for the sort. The expressions do not have to be part of the result
for a simple SELECT, but in a compound SELECT each sort expression
must exactly match one of the result columns. Each sort expression may
be optionally followed by a COLLATE keyword and the name of a
collating function used for ordering text and/or keywords ASC or DESC
to specify the sort order.
Which i can't decide if means it's impossible or i should try harder.
try this
SELECT RowType
, id
, DATE
, title
FROM
(
SELECT 'album' AS RowType , id , DATE , title , time_added
FROM albums
WHERE is_temp = 0 AND subject_id = '3'
UNION ALL
SELECT 'video' AS RowType , id , DATE , title , time_added
FROM videos
WHERE is_temp = 0 AND subject_id = '3'
UNION ALL
SELECT 'story' AS RowType , id , DATE , title , time_added
FROM stories
WHERE is_temp = 0 AND subject_id = '3'
) s
ORDER BY DATE , time_added

Balancing out MYSQL select statements

I inserted 'vanity_name' and 'name' into the first and second SELECT statements respectively.
I get a mismatched number of columns error, which I'm confused about because I added a column to both select statements to maintain a balance.
SQL Statement:
SELECT id,
vanity_name,
Date_format(DATE, '%M %e, %Y') AS DATE,
TYPE
FROM (SELECT resume_id AS id,
date_mod AS DATE,
'resume' AS TYPE
FROM resumes
WHERE user_id = '1'
UNION ALL
SELECT profile_id,
name,
date_mod AS DATE,
'profile'
FROM profiles
WHERE user_id = '1'
ORDER BY DATE DESC
LIMIT
5) AS d1
ORDER BY DATE DESC
Erm, you have four columns in your outer select, three in the inner select.
id, vanity_name, date, type
vs.
id, date, TYPE
Based on the parenthesis, you're trying to union:
(SELECT resume_id AS id, date_mod AS date, 'resume' AS TYPE FROM resumes WHERE user_id = '1'
with
SELECT profile_id,name,date_mod AS date, 'profile' FROM profiles ... LIMIT 5)
and they obviously don't match. Reposition your parens.

mysql group and sort a UNION

In my guestbook I have 2 tables: messages and replies.
Now, I want to get all messages grouped by id (means that message and corresponding replies will be grouped/together) and sorted by date DESC (the newest messages will be first; if a message is the oldest one, but the corresponding reply is the newest of all messages, this group will be on the top of the table), while replies will be sorted by date ASC (oldest reply on the top).
Here my mysql query that works good except it doesnt sort replies by date ASC
SELECT msg.id as id, msg.comment, msg.date_added as date_added, 0 as is_reply
FROM messages AS msg
UNION
SELECT reply.msg_id as id, reply.comment, reply.date_added as date_added, 1 as is_reply
FROM pg_reply as reply
GROUP BY id
ORDER BY date_added DESC, is_reply ASC
is_reply ASC doesnt do the job as I supposed
reply.msg_id specifies id of reply's parent (messages.id)
What the result should look like>
- message A
- oldest reply B
- old reply C
- new reply Z // this is the newest message in the guestbook
- newer message E // is newer than A but older than the newest message in the guestbook, which is Z
- reply F // (this reply is newer than all messages but message Z)
For this answer I'm going to assume that reply.msg_id is a linkfield to the original message.
SELECT id, comment, date_added, is_reply FROM (
SELECT
msg.id as id
, msg.comment
, msg.date_added as date_added
, 0 as is_reply
FROM messages AS msg
UNION
SELECT
reply.msg_id as id
, reply.comment
, reply.date_added as date_added
, 1 as is_reply
FROM pg_reply as reply ) AS allmsg
ORDER BY id DESC, is_reply, date_added DESC
This works assuming that msg_id is an autoincrement field and that newer id's also have a newer date_added timestamp.
Remarks on the original code
In your original code you have
GROUP BY id
ORDER BY date_added DESC, is_reply ASC
The GROUP BY implicitly orders on id ASC; the following ORDER BY overrides that and orders by date_added first and is_reply second.
However if date_added is a datetime then the chance of two post having the same time are remote (esp. for replies, it takes time to write them),
so the 2nd order clause hardly ever gets used.
GROUP BY should only be used if you have an aggregate function in your select, such as SUM or COUNT
If you want to remove duplicates from your select do not use group by, use distinct as in select distinct a,b,c from table1 where ...
similar solution:
SELECT sort, project, reviewdate, reviewby, subject, venue, filename, remarks1, remarks2, url
FROM (
SELECT '1' AS sort, project, last_updated AS reviewdate, reviewby, concat( project, '(',
TYPE , '): ', subject ) AS subject, venue, filename, remarks1, remarks2, concat( project, '/',
TYPE , '/', filename ) AS url
FROM `upload_cmg`
WHERE (
(
subject LIKE '%prt%'
OR project LIKE '%prt%'
OR TYPE LIKE '%prt%'
)
AND (
subject LIKE '%mouda%'
OR project LIKE '%mouda%'
OR TYPE LIKE '%mouda%'
)
)
UNION SELECT '2' AS sort, project, last_updated AS reviewdate, reviewby, concat( project, '(',
TYPE , '): ', subject ) AS subject, venue, filename, remarks1, remarks2, concat( project, '/',
TYPE , '/', filename ) AS url
FROM `upload_cmg`
WHERE subject LIKE '%mouda%'
GROUP BY url
) AS vin
ORDER BY sort, reviewdate DESC
I would recommend adding a message parent field in both and sorting on that as your primary sort, with date then being the sort after that.. otherwise you will have replies showing up mixed up with other messages that were posted between replies. You can have the message parent of a non-reply message be itself.
Try this:
SELECT id, comment, date_added, is_reply
FROM (
SELECT msg.id as id, msg.comment, msg.date_added as date_added, 0 as is_reply
FROM messages AS msg
INNER JOIN pg_reply as reply
ON reply.msg_id = msg.id
GROUP BY msg.id, msg.comment, msg.date_added, 0 as is_reply
ORDER BY CASE WHEN MAX(reply.date_added) > msg.date_added THEN MAX(reply.date_added) ELSE msg.date_added END DESC
UNION
SELECT reply.msg_id as id, reply.comment, reply.date_added as date_added, 1 as is_reply
FROM pg_reply as reply
ORDER BY date_added ASC ) a
ORDER BY id