SELECT with MySQL a specific date from a range - mysql

i've two tables
Table A: a_id,timemarker (datetime)
Table B: b_id,start (datetime), stop(datetime), cat(varchar)
table A
149|2010-07-19 07:43:45
150|2010-07-19 08:01:34
151|2010-07-19 07:49:12
table B
565447|2010-07-19 07:30:00|2010-07-19 08:00:00
565448|2010-07-19 08:00:00|2010-07-19 08:20:00
i want select all rows from Table A who are in the range of Table B
thanks

Select any A that is within ANY [B.start, B.end]
select a.*
from
table a
where exists ( select * from table b where a.timemarker between b.start and b.stop)
;
The OP writes
i have trouble with my keys! the query executes very long. i have got in table a over 40k rows and in table b over 1.4 million rows... there is no relation within the tables – Norman 3 secs ago
Yes, because you're potentially comparing each A with every B = 40k * 1.4M comparisons.
But your question was "how do I do this", not "here's how I'm doing it, how can I make it faster".
if you want it faster, you'll need to add an index on B(start, end);

SELECT a.* FROM a
INNER JOIN b ON
a.timemarker BETWEEN b.start AND b.end
GROUP BY a.id
I think this should be less expensive. Of course an extra index will help, too :)

Related

Looking for a low footprint solution to GROUP rows using HAVING to filter

Here is a table
id date name
1 180101 josh
2 180101 peter
3 180101 julia
4 180102 robert
5 180103 patrick
6 180104 josh
7 180104 adam
I need to get all the names whom having the same days as 'josh'. how can i achieve it without groupping the whole table together. i need to keep it efficient (this is not my real table, i just simplified my problem here, and i have hundred thousands of records, and 99% of the rows have different dates, so groupable rows by date is kind of rare).
So basicaly what i want is: if 'josh' is the target, i need to get 'josh,peter,julia,adam' (actually the first 10 distinct names sharing the same date with josh).
SELECT
COUNT(date) as datecount,
GROUP_CONCAT(DISTINCT name) as names,
FROM
table
GROUP BY
date
HAVING
datecount>1
// && name IN ('josh') would work nice for me, but im getting error because 'name' is not in GROUPED BY
LIMIT 10
Any idea ? As i mentioned it needs to be fast, and most of the rows have unique dates
Join the table with itself on date:
select distinct t1.name
from tbl t1
join tbl t2 using (date)
where t2.name = 'josh'
Demo
For the best performance you would have indexes on (name) and (date, name).

Temp Table Creation in SQL

Could someone help me with this? I have couple of tables with some data. I need to query this table for the number of rows processed per day and load into another table:
Table1:
PNO ModelNo OrderNo CustID DAY
1 100012 1000AY 2345 31-AUG
2 109014 100YT8 3452 01-AUG
2 109014 100YT8 3452 31-AUG
Table2:
AN DAST CODE ROWS DAY
19 VEN EFD 19 31-AUG
21 EHT UYE 21 01-SEP
22 VEG WTE 24 01-SEP
Final Table:
DAY Source Rows
31-AUG Table1 2
01-SEP Table1 1
31-AUG Table2 1
01-SEP Table2 2
*Source: should be the table name.
Should I have to use Temp table or create a inner query concept and do it? Would like to know which is effecient. Please help.
Keep you updated: that all of these table are created under same schema..
As Shaharyar suggests, the reasons for actually creating such a table are probably questionable at best. However, the query to create the resulting table:
SELECT 'Table1' as Source, COUNT(*) as Rows, DAY FROM Table1 GROUP BY DAY
UNION
SELECT 'Table2' as Source, COUNT(*) as Rows, DAY FROM Table2 GROUP BY DAY
This doesn't scale very well for many tables. Though. Also, it would be preferable to add indexes on the DAY columns.
If you actually want to generate a manifested table, this might do the job:
CREATE TABLE final_table SELECT ...

Mysql query to count from A where not in B

I got a table A and a table B (and a Table C which is not really relevant). The relation is 1:n.
Table A
- id
- c_foreign_key
Table B
- id
- A_id
- datetime
Table A has about 400'000 entries, table B about 20 million.
I have a time-range, lets say from 2014/01/01 to 2014/12/31.
What i want for each month in this range is:
Count all entries from table A, grouped by c_foreign_key, where table A has no entries in table B for (month - 1.year to month).
The Result should look like this:
date c_foreign_key count(*)
--------------------------------
14/01 1 2000
14/01 2 3000
...
14/02 1 4000
14/01 2 6000
...
I already tried left join and "not in select" for each month the performance wasn't really good.
You should debug your SQL queries with explain more info at Mysql Explain Syntax, also you should place index- es on your datetime fields for a better performance. Explain usualy is used to see which indexes does mysql use in your query.

How to join two tables without primary key or unique key?

I have two tables named LocalVSDB and TemporaryVSDB. Both tables have the same columns:
LocalVSDB: msisdn,activateDate
TemporaryVSDB: msisdn,activateDate
But both tables also have duplicate rows for MSIDSN
I need to join these two tables. My intended result looks like this:
MSISDN LocalActivateDate TemporaryActivateDate Datediff
60103820251 2013-12-14 2013-10-05 70
601111000254 2013-12-14 2013-10-05 70
601111000254 2013-12-18 2013-09-10 80
But, since there are duplicate MSIDSNs, I am getting duplicate rows when I join. For example there are 6 rows for certain MSISDN in each table so when I am joining I am getting total 36 rows for that MSISDN.
I am joining using the following query:
SELECT t.msisdn,t.activateDate AS VSDB_Activate_Date,
l.activateDate AS Local_Activate_Date,
DATEDIFF(D,l.activateDate,t.activateDate) AS date_Diff
FROM temporaryVSDB2 t
INNER JOIN LocalVSDB l ON t.msisdn = l.msisdn
WHERE t.activateDate > l.activateDate
Please help me how can I get 6 rows for 6 MSISDN?
Thanks in advance.
The problem is:
where t.activateDate > l.activateDate
That means one row in table one can join to all six rows in table two. You either need to change this to an = or just get a single row from the second table based on certain criteria.
SELECT m.MSIDN, m.ActiveDate, t.ActiveDate, DATEDIFF(DAY, m.ActiveDate, t.ActiveDate) Duration
FROM LocalVSDB m
OUTER APPLY
(
SELECT TOP 1 d.MSIDN, d.ActiveDate
FROM TemporaryVSDB d
WHERE d.ActiveDate > m.ActiveDate
ORDER BY d.ActiveDate
) t
This would find the nearest partner record and duration (the last record will have a null partner though)
You can use your own query adding group by clause provided msidn and activateDate produce unique row.
SELECT t.msisdn,t.activateDate AS VSDB_Activate_Date,
l.activateDate AS Local_Activate_Date,
DATEDIFF(D,l.activateDate,t.activateDate) AS date_Diff
FROM temporaryVSDB2 t INNER JOIN LocalVSDB l ON t.msisdn = l.msisdn
WHERE t.activateDate > l.activateDate
group by t.msisdn, t.activateDate

How to perform a complex range query in MySQL

I have a table (Table A) with a field of integers (Field B). For each row of Table A, I would like to construct a range of +/- 100 surrounding the integer value of Field B then find all values from Field B that are within these ranges. The query needs to be performed for all values in Field B. The query needs to return each row that is within each row range. Here is an example of what I am trying to do:
Table A
_______
A 1000
B 3000
C 5000
D 1090
Using the above Table A, the query would first find the ranges (+/- 100) for all integers in Field B.
900 - 1100
2900 - 3100
4900 - 5100
990 - 1190
The query would then iterate through these ranges and return rows from Table A that fall within the generated ranges. Using the above example, the query would return:
A 1000
A 1000
B 3000
C 5000
D 1090
D 1090
A and D are returned twice because it they fall within their own ranges. How can I construct a query that will return each row that falls between the range of each row? Thanks in advance for the help.
SELECT t2.*
FROM tableA AS t1
INNER JOIN tableA AS t2 ON t2.fieldB >= (t1.fieldB - 100) AND t2.fieldB <= (t1.fieldB + 100)
Shouldn't A also be shown twice, since it's also in D's range? (that's the case with above query - if incorrect, please elaborate why ^^)
Start with your inner-most pre-qualifier of every Table A record... Then re-join to table A again. I've added the qualifying Group ranges low and hi to show the qualifier basis you were looking for... In addition to D showing up twice, A should show up twice too as it qualifies the "D"s range too.
select
a2.ShowLetter,
a2.FieldB,
GrpRanges.RangeLow,
GrpRanges.RangeHi
from
( select distinct
a1.FieldB - 100 as RangeLow,
a1.FieldB + 100 as RangeHi
from
TableA a1 ) GrpRanges
JOIN TableA a2
on a2.FieldB between GrpRanges.RangeLow and GrpRanges.RangeHi
order by
a2.ShowLetter