Selecting the second column in a complex mysql query - mysql

I'm trying to create a query for reporting purposes and I'm failing when i try to select the date (second column) from multiple joins (selects).
The query is something like this:
SELECT a.Name, COALESCE(a.CustomerFaxes,0) AS 'CustomerFaxes', COALESCE(b.PoliceFaxes,0) AS 'PoliceFaxes', COALESCE(c.CustomerWebposts,0)AS 'CustomerWebposts', COALESCE(d.PoliceWebposts,0) AS 'PoliceWebposts', COALESCE(e.Letters,0) AS 'Letters'
FROM jobs j
LEFT JOIN (SELECT ...
GROUP BY 1,2) a ON ...
LEFT JOIN (SELECT ...
GROUP BY 1,2) b ON ...
LEFT JOIN (SELECT ...
GROUP BY 1,2) c ON ...
LEFT JOIN (SELECT ...
GROUP BY 1,2) d ON ...
LEFT JOIN (SELECT ...
GROUP BY 1,2) e ON ..
JOIN table cu ON ...
JOIN table2 a ON ...
WHERE j.UserID IN (1,2,3,4,5,6,7,8,9)
AND j.receivedontime BETWEEN UNIX_TIMESTAMP (20150302) AND UNIX_TIMESTAMP (20150310)
GROUP BY 1;
This results in something like
User CustomerFaxes PoliceFaxes CustomerWebposts PoliceWebposts Letters
There are a lot of conditions in between. All sub queries have the second value as a date, i want to select it and group by it.
Any of you know a way?

A few things
First, this is going to cause you a headache
COALESCE(a.value2,0) AS 'value2', COALESCE(b.value2,0) AS 'value2'
You are trying to give two different columns in the same result set the same name.
Based on your comments, it sounds like what you really want is to get all date values in one column, using the date field from a first, then b, then c. You can do this by plugging them all into a single coalesce statement.
COALESCE(a.date,b.date,c.date) as Date
Second, you should probably know that column order is not particularly significant in SQL. You never select columns by column number. Naming your columns with an idex is confusing (what if someone reorders your query?) and doesn't help other users figure out what your query is trying to do. In the long run, readability matters more than anything else. You don't want to come back 6 months later and wonder what the heck your query was supposed to do.
Third, don't use date as a column name. Date is a resevered keyword in most implementations of SQL. Use a more informative name like 'DateRecieved' or 'DateOpened' or 'DateOfBirth' or 'TheDateTheEarthStoodStill'.

Just use column names rather than numbers, and then select it from the relevant subquery - it's as simple as that.
For example -
SELECT c.Date AS Date
or
SELECT d.Date AS Date
whichever subquery you want the Date from, just use that.

Related

SELECT multiple columns from multiple tables and don't fill blank spaces

I have what I believe to be a pretty unique use case. I would like to be able to runs a single SELECT statement on a database where I get one column from four tables. I need to run where clauses on each different table where I have one main clause that will be across each of the tables and I am not able to JOIN because the data in each column will be a different length and I don't want to have duplicate items.
I have an example of the Select statement below. Also I understand if this is not possible.
SELECT s.service_id, u.id AS "user_id", h.mac_address, l.id AS "location_id" FROM services s
LEFT JOIN db.av_product ap ON s.product_id = ap.id
WHERE s.customer_code LIKE 'test_customer'
AND u.customer_code LIKE 'test_customer'
AND h.customer_code LIKE 'test_customer'
AND l.customer_code LIKE 'test_customer'
AND s.parent_id IS NULL
AND s.active=0
AND ap.sku NOT REGEXP 'fakeregex'
AND l.active = "1"
AND h.hardware_id NOT IN ('44','45')
AND (u.support_user != 1 OR u.support_user IS NULL);
TIA!
You will need to use joins for your tables to make a single query OR you can try multiple queries merged with UNION keyword.
If you want to make a single query, have a look about SELECT DISTINCT or GROUP BY for handling duplicates.
wut up?
do you know what UNION is?
The UNION operator is used to combine the result-set of two or more SELECT statements.
but every SELECT statement within UNION must have the same number of columns; so there we got a problem.
you can handle it with WHERE operator so I won't get in to it.
anyway, UNION!
shall we?
SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2;
anyway; your solution is UNION, maybe not like what I wrote.
you can try this link too.
https://www.w3schools.com/mysql/mysql_union.asp
have a clean code

MySQL GROUP BY ignores the ORDER BY and always returns the 1st row

I have read through tons of similar questions and none is answering what is wrong with mine.
I want to select the entire row that includes the maximum value of one of the columns for each group.
SELECT * FROM (
SELECT t1.* FROM `t1` JOIN `t2` ON t2.id=t1.raceId ORDER BY t1.points DESC
) AS new GROUP BY new.athleteId ORDER BY new.points DESC
This works, giving me a single row for each athlete, but the row it shows is just the earliest row in the DB, not the row with the maximum points.
The sub query alone shows all the rows in the correct order, but when I try to group them, it still takes the earliest row and ignores the ordering.
I can retrieve the maximum points for each grouping, but the rest of the row info still comes from the earliest entry.
The GROUP BY clause is meant to be used with aggeregate functions.
What is it that you are trying to achieve with the GROUP BY?
Maybe one way to achieve what you're after..
As a general rule of thumb; it's wise if you're using a "GROUP BY" to define what aggregate functions to use. MySQL allows you to group by without aggerate functions defined but i've found this to be very confusing whiteout being very specific on what I want to aggregate on. Maybe it's because of my background in SQL server and oracle; which DO NOT allow you to use a group by this way...
essentially get the max points for each athlete then join back to your entire data set to limit by that athlete and points. may need to do it by race if you want athlete by race as well, i'm unsure if you want max athlete points by race, but based on the group by/order by I'm guessing not.
SELECT t1.*, t2.*
FROM (SELECT athlete, max(t1.points)
FROM `t1`
INNER JOIN `t2` ON t2.id=t1.raceId
GROUP BY athlete) new
INNER JOIN `t1` on T1.athletID = new.athletID
and t1.points = new.points
INNER JOIN JOIN `t2` ON t2.id=t1.raceId
ORDER BY new.points DESC
Another way depending on version of mySQL would be to use analytic functions along with aggregate functions... but w/o version number, i'll not go into detail.

How to add a column of a constant value from a query to another query result?

Basically, I have two tables. From table A, I want to calculate the total number of rows from it. I can use SELECT COUNT(*) FROM A as the first query to get it. From other table B, I want to select all things(columns) from it. I can use SELECT * FROM B as the second query. My question is how to use a single query to add the result from the first query as a column to the second query result. In other words, I want to have an extra column with the value of total number of rows from Table A to all things from Table B, by using a single query.
CROSS JOIN it:
SELECT * FROM
(SELECT COUNT(*) as cnt FROM A) a
CROSS JOIN
B
Join makes the resultset wider. Union makes the resultset taller. Any time you want to grow the number of columns you have to join, but if you haven't got anything to join ON you can use a CROSS JOIN as it doesn't require any ON predicates
You could alternatively use an INNER JOIN with a predicate that is always true, an old style join syntax without any associated WHERE, or you can put a select that returns a single value as a subquery in the select list area without any co-ordinating predicates. Most DBA would probably assert that none of these are preferable to the CROSS JOIN syntax because CROSS JOIN is an explicit statement of your intent, whereas the others might just look like you forgot something

Can I maintain the output of INNER JOIN to be sorted based on the order of the left side table (the 1st table)?

In PostgreSQL - in the following query I perform an INNER JOIN on two tables -
the 1st table (patient_bvi_p) is SORTED. I extract the gene name (a simple string) from the "id4" column and then using this value for performing the INNER JOIN with the 2nd table (geneexpressoin17p).
My issue is that after performing the INNER JOIN the result of my query is all scrambled.
The rows are no longer being sorted based on the left hand table (patient_bvi_p) while I really need/want them to be.
Can someone please explain what is the behavior one should expect after performing an INNER JOIN? Shouldn't the output be sorted in the same way the the left (/first) table was sorted?
Is there a way to maintain somehow the original order? OR - I should always assume that after INNER JOIN the resultant output is unsorted (=scrambled) - and therefore I should perform an extra sorting step AFTER the doing the the INNER join?...
My motivation is basically to avoid an extra sorting step and to rely on the original order of my first table.
select
t1.* ,
bvi_d_exp,
bvi_r_exp,
bvi_exp.bvi_lr_rvd
into Patient_bvi_p_exp
from
(
select split_part(id4, '#', 3) genes, *
from patient_bvi_p
) t1
inner join (
select
genename,
bvi_d_exp,
bvi_r_exp,
bvi_lr_rvd
from geneexpression17p
) bvi_exp on lower(t1.genes) = lower(bvi_exp.genename)
The order of rows in a query output is undefined if there is no order by clause. Postgres will output in any way it sees fit. If you want the output to be ordered you must specify an order by. In other words, you should not rely on output order like you describe, it could change if it is not specified. That said, in your example:
select t1.* ,bvi_d_exp,bvi_r_exp,bvi_exp.bvi_lr_rvd
into Patient_bvi_p_exp
from (select split_part(id4, '#', 3)genes,* from patient_bvi_p)
t1 inner join (select genename,bvi_d_exp,bvi_r_exp,bvi_lr_rvd
from geneexpression17p) bvi_exp on lower(t1.genes)= lower(bvi_exp.genename);
I think you are saying that if you do this:
select * from Patient_bvi_p_exp;
You get random ordering. Yes, that is true. Again, don't rely on order. However, you could:
select t1.* ,bvi_d_exp,bvi_r_exp,bvi_exp.bvi_lr_rvd
into Patient_bvi_p_exp
from (select split_part(id4, '#', 3)genes,* from patient_bvi_p)
t1 inner join (select genename,bvi_d_exp,bvi_r_exp,bvi_lr_rvd
from geneexpression17p) bvi_exp on lower(t1.genes)= lower(bvi_exp.genename)
order by bvi_d;
And that will cause your table to be ordered by the bvi_d column (or whichever you want). So, a simple select on that table will probably return it in the correct order. Or, if you already ran your first query, you could:
create index whatever on Patient_bvi_p_exp(bvi_d);
cluster Patient_bvi_p_exp using whatever;
And this would physically reorder the table such that a simple select would return it in the order you desire.
I have to say again, you are safer doing:
select * from Patient_bvi_p_exp order by bvi_d;
the 1st table (patient_bvi_p) is SORTED
There is no "sorted" table in SQL. If you want a sorted result then use the order by clause

MySQL Joins, Group By, and Ordering the Group By Choice

Is it possible to order the GROUP BY chosen results of a MySQL query w/out using a subquery? I'm finding that, with my large dataset, the subquery adds a significant amount of load time to my query.
Here is a similar situation: how to sort order of LEFT JOIN in SQL query?
This is my code that works, but it takes way too long to load:
SELECT tags.contact_id, n.last
FROM tags
LEFT JOIN ( SELECT * FROM names ORDER BY timestamp DESC ) n
ON (n.contact_id=tags.contact_id)
WHERE tags.tag='$tag'
GROUP BY tags.contact_id
ORDER BY n.last ASC;
I can get a fast result doing a simple join w/ a table name, but the "group by" command gives me the first row of the joined table, not the last row.
I'm not really sure what you're trying to do. Here are some of the problems with your query:
selecting n.last, although it is neither in the group by clause, nor an aggregate value. Although MySQL allows this, it's really not a good idea to take advantage of.
needlessly sorting a table before joining, instead of just joining
the subquery isn't really doing anything
I would suggest carefully writing down the desired query results, i.e. "I want the contact id and latest date for each tag" or something similar. It's possible that will lead to a natural, easy-to-write and semantically correct query that is also more efficient than what you showed in the OP.
To answer the question "is it possible to order a GROUP BY query": yes, it's quite easy, and here's an example:
select a, b, sum(c) as `c sum`
from <table_name>
group by a,b
order by `c sum`
You are doing a LEFT JOIN on contact ID which implies you want all tag contacts REGARDLESS of finding a match in the names table. Is that really the case, or will the tags table ALWAYS have a "Names" contact ID record. Additionally, your column "n.Last". Is this the person's last name, or last time something done (which I would assume is actually the timestamp)...
So, that being said, I would just do a simple direct join
SELECT DISTINCT
t.contact_id,
n.last
FROM
tags t
JOIN names n
ON t.contact_id = n.contact_id
WHERE
t.tag = '$tag'
ORDER BY
n.last ASC