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
Related
I'm attempting to create an SQL query that retrieves the total_cost for every row in a table. Alongside that, I also need to collect the most dominant value for both columnA and columnB, with their respective values.
For example, with the following table contents:
cost
columnA
columnB
target
250
Foo
Bar
XYZ
200
Foo
Bar
XYZ
150
Bar
Bar
ABC
250
Foo
Bar
ABC
The result would need to be:
total_cost
columnA_dominant
columnB_dominant
columnA_value
columnB_value
850
Foo
Bar
250
400
Now I can get as far as calculating the total cost - that's no issue. I can also get the most dominant value for columnA using this answer. But after this, I'm not sure how to also get the dominant value for columnB and the values too.
This is my current SQL:
SELECT
SUM(`cost`) AS `total_cost`,
COUNT(`columnA`) AS `columnA_dominant`
FROM `table`
GROUP BY `columnA_dominant`
ORDER BY `columnA_dominant` DESC
WHERE `target` = "ABC"
UPDATE: Thanks to #Barmar for the idea of using a subquery, I managed to get the dominant values for columnA and columnB:
SELECT
-- Retrieve total cost.
SUM(`cost`) AS `total_cost`,
-- Get dominant values.
(
SELECT `columnA`
FROM `table`
GROUP BY `columnA`
ORDER BY COUNT(*) DESC
LIMIT 1
) AS `columnA_dominant`,
(
SELECT `columnB`
FROM `table`
GROUP BY `columnB`
ORDER BY COUNT(*) DESC
LIMIT 1
) AS `columnB_dominant`
FROM `table`
WHERE `target` = "XYZ"
However, I'm still having issues figuring out how to calculate the respective values.
You might get close, if we want to get percentage values we can try to add COUNT(*) at subquery to get max count by columnA and columnB then do division by total count
SELECT
SUM(cost),
(
SELECT tt.columnA
FROM T tt
GROUP BY tt.columnA
ORDER BY COUNT(*) DESC
LIMIT 1
) AS columnA_dominant,
(
SELECT tt.columnB
FROM T tt
GROUP BY tt.columnB
ORDER BY COUNT(*) DESC
LIMIT 1
) AS columnB_dominant,
(
SELECT COUNT(*)
FROM T tt
GROUP BY tt.columnA
ORDER BY COUNT(*) DESC
LIMIT 1
) / COUNT(*) AS columnA_percentage,
(
SELECT COUNT(*)
FROM T tt
GROUP BY tt.columnB
ORDER BY COUNT(*) DESC
LIMIT 1
) / COUNT(*) AS columnB_percentage
FROM T t1
If your MySQL version supports the window function, there is another way which reduce table scan might get better performance than a correlated subquery
SELECT SUM(cost) OVER(),
FIRST_VALUE(columnA) OVER (ORDER BY counter1 DESC) columnA_dominant,
FIRST_VALUE(columnB) OVER (ORDER BY counter2 DESC) columnB_dominant,
FIRST_VALUE(counter1) OVER (ORDER BY counter1 DESC) / COUNT(*) OVER() columnA_percentage,
FIRST_VALUE(counter2) OVER (ORDER BY counter2 DESC) / COUNT(*) OVER() columnB_percentage
FROM (
SELECT *,
COUNT(*) OVER (PARTITION BY columnA) counter1,
COUNT(*) OVER (PARTITION BY columnB) counter2
FROM T
) t1
LIMIT 1
sqlfiddle
try this query
select sum(cost) as total_cost,p.columnA,q.columnB,p.columnA_percentage,q.columnB_percentage
from get_common,(
select top 1 columnA,columnA_percentage
from(
select columnA,count(columnA) as count_columnA,cast(count(columnA) as float)/(select count(columnA) from get_common) as columnA_percentage
from get_common
group by columnA)s
order by count_columnA desc
)p,
(select top 1 columnB,columnB_percentage
from (
select columnB,count(columnB) as count_columnB, cast(count(columnB) as float)/(select count(columnB) from get_common) as columnB_percentage
from get_common
group by columnB) t
order by count_columnB desc)q
group by p.columnA,q.columnB,p.columnA_percentage,q.columnB_percentage
so if you want to get the percent and dominant value you must make their own query like this
select top 1 columnA,columnA_percentage
from(
select columnA,count(columnA) as count_columnA,cast(count(columnA) as float)/(select count(columnA) from get_common) as columnA_percentage
from get_common
group by columnA)s
order by count_columnA desc
then you can join with the sum query to get all value you want
hope this can help you
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;
I have a table with 3 columns id, type, value like in image below.
What I'm trying to do is to make a query to get the data in this format:
type previous current
month-1 666 999
month-2 200 15
month-3 0 12
I made this query but it gets just the last value
select *
from statistics
where id in (select max(id) from statistics group by type)
order
by type
EDIT: Live example http://sqlfiddle.com/#!9/af81da/1
Thanks!
I would write this as:
select s.*,
(select s2.value
from statistics s2
where s2.type = s.type
order by id desc
limit 1, 1
) value_prev
from statistics s
where id in (select max(id) from statistics s group by type) order by type;
This should be relatively efficient with an index on statistics(type, id).
select
type,
ifnull(max(case when seq = 2 then value end),0 ) previous,
max( case when seq = 1 then value end ) current
from
(
select *, (select count(*)
from statistics s
where s.type = statistics.type
and s.id >= statistics.id) seq
from statistics ) t
where seq <= 2
group by type
I am trying to change 'from_user' with a parameter from the other table and it doesn't work but when I am using the same table it works like a charm:
SELECT from_user, message_contents, message_read, to_user, date
FROM table1
WHERE date IN (
SELECT MAX( date )
FROM table1
WHERE to_user = 1 GROUP BY from_user
)
ORDER BY from_user ASC , date DESC
but this one just show one record but not all latest ones:
SELECT table2.`display_name`, message_contents, message_read, to_user, date
FROM table1, table2
WHERE table1.`from_user` = table2.`ID`
AND date IN ( SELECT MAX( date )
FROM table1
WHERE to_user = 1 GROUP BY from_user
)
ORDER BY from_user ASC , date DESC
Can anybody help to change 'from_user' with table2.display_name parameter but to get all recent records from mySQL?
You are joining two tables on table1.from_user = table2.id
So, if you don't want that table two to affect the number of rows than you can make a query like this:
SELECT
table1.from_user,
table2.`display_name`,
message_contents,
message_read,
to_user,
date
FROM table1
LEFT JOIN table2 ON table1.`from_user` = table2.`ID`
WHERE
date IN (SELECT MAX(date) FROM table1 WHERE to_user = 1 GROUP BY from_user)
ORDER BY from_user ASC , date DESC
I added also table1.from_user on the select clause which will help you see the from users which don't have a display name.
This is an extract sql that gets days
AND S.Date IN
(
SELECT Date
FROM
(
SELECT Date,
ROW_NUMBER() OVER (ORDER BY Date DESC )-1 Day
FROM CALENDAR_DIM
WHERE TYPE = 'ABC'
)
WHERE BUS_DAY BETWEEN 0 AND 2
)
I want to run this code twice in two parts of my sql. How can i do that without pasting the same code. Also .. how could i rewrite the above code?. I am having some issues with performance.
Solution 1 : use a WITH statement
WITH dateQuery AS (
SELECT Date
FROM
(
SELECT Date,
ROW_NUMBER() OVER (ORDER BY Date DESC )-1 BUS_DAY
FROM CALENDAR_DIM
WHERE TYPE = 'ABC'
)
WHERE BUS_DAY BETWEEN 0 AND 2)
SELECT xxx
FROM yyy
WHERE zzz
AND s.Date IN (SELECT Date FROM dateQuery)
The only part to repeat will then be
SELECT Date FROM dateQuery
Solution 2 : create a View
CREATE OR REPLACE VIEW V_DATE_QUERY AS
( SELECT Date
FROM
(
SELECT Date,
ROW_NUMBER() OVER (ORDER BY Date DESC )-1 BUS_DAY
FROM CALENDAR_DIM
WHERE TYPE = 'ABC'
)
WHERE BUS_DAY BETWEEN 0 AND 2)
and use it the same way
AND s.Date IN (Select Date FROM V_DATE_QUERY);
You would make this a view in your database like so:
CREATE VIEW view_date
AS
SELECT Date,
ROW_NUMBER() OVER (ORDER BY Date DESC )-1 Day
FROM CALENDAR_DIM
WHERE TYPE = 'ABC'
Now you can use:
AND S.Date IN
(
SELECT Date
FROM view_date
WHERE BUS_DAY BETWEEN 0 AND 2
)