optimising multi pass join in mysql - mysql

I have a single table and want to get distinct values from each column.
select distinct 'customer', customer from sales
union
select distinct 'product',product from sales
In the example, MySQL does two full passes of the (huge) table.
I'm trying to get distinct values from many columns, so in fact the query would do 6 full passes of the table. Indexing isn't an option in this case.
How can I persuade MySQL to do this in a single pass ?

You can try unpivot approach
SELECT DISTINCT
CASE WHEN type = 1 THEN 'customer'
WHEN type = 2 THEN 'product'
END type,
CASE WHEN type = 1 THEN customer
WHEN type = 2 THEN product
END value
FROM sales s CROSS JOIN
(
SELECT 1 type UNION ALL
SELECT 2
) t
ORDER BY type
Here is SQLFiddle demo

Related

MySQLi query only one type of result

I am trying to query all the results for only one type of message from the database:
Table:
ID List Content
1 8 This
2 8 That
3 9 Other
4 8 Last
There will be about 20,000 rows in this table, so I don't want to select them all and then sort through them if I don't have to. Basically, the List numbers will be changing, so I won't know what they are, but I only want to query results where List is the same.
It's a cron job script that will be removing these from the table after it's ran, so it doesn't matter what the List is, as long as each query returns all the same List.
What's the way of doing this straight from the MySQLi query without knowing what List is?
SELECT * FROM Table WHERE List = 8
You seem to want to select rows where list is duplicated. To get the rows with the most duplication, you can use:
select t.*
from table t join
(select list, count(*) as cnt
from table
group by list
order by count(*) desc
limit 1
) tt
on t.list = tt.list;
If you want any rows where list is duplicated, you can remove the having clause.
Here's a way using exists to select all rows where another row with the same List value exists.
select * from mytable a
where exists (
select 1 from mytable b
where b.List = a.List
and b.Id <> a.Id
)

MySQL view count and sum and other operations from multiple tables

Here is my situation:
I have 4 tables that all contains a column called score in all of these tables my goal for a view to create operations to the result of the 4 tables getting the following values:
Total score
Total number of rows
average (total score / number of rows)
Now i know that i would be able to create the view as:
(SELECT * FROM table1 where condition) + (SELECT * FROM table2 where condition)
So on and so forth.
but for each of the three goals i have i would have to nested select all tables atleast 2 times.
So my question is how do you handle a case like this? is there any operation in sql that makes this an easy task or am i bound to do something redundant?
Update
So my full case is that every use in my system has something called a division_id now i want to use this ID to find out what the score is for each division:
(PLEASE IGNORE THE _COPY)
You could use a UNION to join the 4 tables, since there is no join condition. There are a couple of ways that you could do this with the division field. Probably the most concise is:
select division_id, count(*), avg(scores.score), sum(scores.score) from
user join
(select id as user_id, score from user
UNION ALL
select user_id, score from test_score
UNION ALL
select user_id, score from task_score
UNION ALL
select user_id, score from offline_score) as scores
on user.id = scores.user_id
group by division_id
Link to SQLFiddle

mysql union getting 2 column names from another table corresponding to 2 id columns

I have a table "task" which stores the details of a task that is created, I need to get the names of the creator ID and the ASSIGNEDTO ID in a single query for which i created a UNION however I get the following error in mysql
Both the select queries execute perfectly as individual queries
#1222 - The used SELECT statements have a different number of columns
SELECT a.task_id, a.task_title,a.task_created_by,a.task_creation_date,b.user_id, b.user_email FROM task a,users b WHERE a.task_created_by = b.user_id
UNION
SELECT a.task_assigned_to, b.user_email FROM task a,users b WHERE a.task_assigned_to = b.user_id
Only selects based on same columns can be subjects to UNION
There's a workaround that implies using "as" for any column that you might not have in the other table. Like this:
SELECT b, '' as c FROM table1
UNION ALL
SELECT b, c FROM table2
Based on this the "c" for table1 will always be empty, but the UNION will still work.
Use this logic to UNION tables that have different columns

Making two SQL queries into one

How can i perform these two queries in one single query, so that it shows the eid that has more than 2 values and shows its eid as well?
select eid, count(Edited_by.eid)
from Edited_by
group by eid;
select Editor.eid
from Editor
where ( select count(*)
from Edited_by
where Edited_by.eid=Editor.eid ) > 2;
UPDATE
A predicate in the HAVING clause can operate on aggregate expressions. I think you may be looking for something like this:
SELECT t.eid
, COUNT(t.eid) AS cnt
FROM Edited_by t
GROUP BY t.eid
HAVING COUNT(t.eid) > 2
Whoops. I entirely missed that the two queries were referencing two different tables.
To also reference the Editor table, you could use the query above as an inline view.
SELECT c.eid AS edited_by_eid
, c.cnt AS cnt
, IF(c.cnt>2,e.Eid,NULL) AS editor_eid
FROM Editor e
JOIN ( SELECT t.eid
, COUNT(t.eid) AS cnt
FROM Edited_by t
GROUP BY t.eid
) c
ON c.eid = e.Eid
FOLLOWUP
Q: "I want to get the result of BOTH queries by running one."
A: I'm not understanding exactly what you want to achieve.
To have two separate resultsets returned, you would need to run two separate statements. MySQL can return multiple resultsets from a stored procedure, for example, a procedure could execute the two queries. The client could process both resultsets (if that's supported and enabled in the client interface library.) That would be a "single statement" (CALL my_procedure;).
If you want to concatenate the results of two separate queries, you could use the UNION ALL set operator. Normally, I would return a discriminator column to distinguish which rows were returned by which query. To do that, the number of columns and the datatypes of each column must match between the two queries.
In the example you give, the query from the Editor table would need to return a dummy integer-type column in order to concatenate the two results.
SELECT t.eid
, COUNT(Edited_by.eid) AS cnt
FROM Edited_by t
GROUP BY t.eid
UNION ALL
SELECT e.eid
, 0 AS cnt
FROM Editor e
WHERE ( SELECT COUNT(*)
FROM Edited_by c
WHERE c.eid=e.eid
) > 2

Select from multiple tables without a join?

What is the easiest way to select data from two tables and rather than join them, have them appear as separate rows. Both tables have similar or matching fields and I want to run some aggregate function on them such as avg all the rows that occurred in the same month, from both tables.
for example I have two tables, one that is shows transactions from one system and another with transactions from a different system. Is there a way to grab all the transactions from both tables as separate rows? if table 1 had twenty records and table 2 have thirty records, I'd like there to be 50 rows on the return.
You could try something like this:
SELECT ...
FROM (
SELECT f1,f2,f3 FROM table1
UNION
SELECT f1,f2,f3 FROM table2
)
WHERE ...
You could try this notattion:
SELECT * from table1,table2
More complicated one :
SELECT table1.field1,table1.field2, table2.field3,table2.field8 from table1,table2 where table1.field2 = something and table2.field3 = somethingelse
Such queries are usually called "implicit JOINs" and Explicit vs implicit SQL joins asks how both compare. In some cases implicit query execution planning is identical to explicit JOINs.
The UNION ALL operator may be what you are looking for.
With this operator, you can concatenate the resultsets from multiple queries together, preserving all of the rows from each. Note that a UNION operator (without the ALL keyword) will eliminate any "duplicate" rows which exist in the resultset. The UNION ALL operator preserves all of the rows from each query (and will likely perform better since it doesn't have the overhead of performing the duplicate check and removal operation).
The number of columns and data type of each column must match in each of the queries. If one of the queries has more columns than the other, we sometimes include dummy expressions in the other query to make the columns and datatypes "match". Often, it's helpful to include an expression (an extra column) in the SELECT list of each query that returns a literal, to reveal which of the queries was the "source" of the row.
SELECT 'q1' AS source, a, b, c, d FROM t1 WHERE ...
UNION ALL
SELECT 'q2', t2.fee, t2.fi, t2.fo, 'fum' FROM t2 JOIN t3 ON ...
UNION ALL
SELECT 'q3', '1', '2', buckle, my_shoe FROM t4
You can wrap a query like this in a set of parenthesis, and use it as an inline view (or "derived table", in MySQL lingo), so that you can perform aggregate operations on all of the rows.
SELECT t.a
, SUM(t.b)
, AVG(t.c)
FROM (
SELECT 'q1' AS source, a, b, c, d FROM t1
UNION ALL
SELECT 'q2', t2.fee, t2.fi, t2.fo, 'fum' FROM t2
) t
GROUP BY t.a
ORDER BY t.a
If your question was this -- Select ename, dname FROM emp, dept without using joins..
Then, I would do this...
SELECT ename, (SELECT dname
FROM dept
WHERE dept.deptno=emp.deptno)dname
FROM EMP
Output:
ENAME DNAME
---------- --------------
SMITH RESEARCH
ALLEN SALES
WARD SALES
JONES RESEARCH
MARTIN SALES
BLAKE SALES
CLARK ACCOUNTING
SCOTT RESEARCH
KING ACCOUNTING
TURNER SALES
ADAMS RESEARCH
ENAME DNAME
---------- --------------
JAMES SALES
FORD RESEARCH
MILLER ACCOUNTING
14 rows selected.
You should try this
SELECT t1.*,t2.* FROM t1,t2
SELECT * from table1
UNION
SELECT * FROM table2
Union will fetch data by row not column,So If your are like me who is looking for fetching column data from two different table with no relation and without join.
In my case I am fetching state name and country name by id. Instead of writing two query you can do this way.
select
(
select s.state_name from state s where s.state_id=3
) statename,
(
select c.description from country c where c.id=5
) countryname
from dual;
where dual is a dummy table with single column--anything just require table to view
select 'test', (select name from employee where id=1) as name, (select name from address where id=2) as address ;
In this case we are assuming that we have two tables:
SMPPMsgLogand SMSService with common column serviceid:
SELECT sp.SMS,ss.CMD
FROM vas.SMPPMsgLog AS sp,vas.SMSService AS ss
WHERE sp.serviceid=5431
AND ss.ServiceID = 5431
AND Receiver ="232700000"
AND date(TimeStamp) <='2013-08-07'
AND date(TimeStamp) >='2013-08-06' \G;
you can try this works always for me
query="SELECT * from tableX,tableY,table8";