If EXISTS (MYSQL) only get this results - mysql

I have a short question an I am stuck at this point. I have the following query:
SELECT A, B
FROM my_table AS r
LEFT JOIN my_table_2 AS p ON r.rs_id = p.rs_id
WHERE r.rs_id = $DB->quote($_SESSION['mysession']['id']) EXISTS (SELECT A, B, date FROM my_table WHERE date = CURDATE())';
What I am trying to do is to get results from the database. If there is a row however that has a record that matches the current date I only want to get this rows, so not all A + B anymore. If there are NO rows with a current date I want to load all A + B by default.
Does anyone knows the answer? Thanks!

To do this in a clean way, you would check on application level, if the query searching for records with date equal to current date returns any records. If not, execute a second query.
You can do the same in MySQL, but since this is in a way a bit "dirty" (the techniques used are not meant to be used this way), I would recommend solving doing this on application level. In case you're curious, here's how:
SELECT SQL_CALC_FOUND_ROWS whatever
FROM table
WHERE date_column = CURDATE()
UNION ALL
SELECT whatever
FROM table
WHERE FOUND_ROWS() = 0;
read more about it here

Related

Join Performances When Searching For NULL Value

I need to find a value that exists in LoyaltyTransactionBasketItemStores table but not in DimProductConsolidate table. I need the item code and its corresponding company. This is my query
SELECT
A.ProductReference, A.CompanyCode
FROM
(SELECT ProductReference, CompanyCode FROM dwhdb.LoyaltyTransactionsBasketItemsStores GROUP BY ProductReference) A
LEFT JOIN
(SELECT LoyaltyVariantArticleCode FROM dwhdb.DimProductConsolidate) B ON B.LoyaltyVariantArticleCode = A.ProductReference
WHERE
B.LoyaltyVariantArticleCode IS NULL
It is a pretty straight forward query. But when I run it, it's taking 1 hour and still not finish. Then I use EXPLAIN and this is the result
But when I remove the CompanyCode from my query, its performance is increasing a lot. This is the EXPLAIN result
I want to know why is this happening and is there any way to get ProductReference and its company with a lot more better performance?
Your current query is rife with syntax and structural errors. I would use exists logic here:
SELECT a.ProductReference, a.CompanyCode
FROM dwhdb.LoyaltyTransactionsBasketItemsStores a
WHERE NOT EXISTS (SELECT 1 FROM dwhdb.DimProductConsolidate b
WHERE b.LoyaltyVariantArticleCode = a.ProductReference);
Your current query is doing a GROUP BY in the first subquery, but you never select aggregates, but rather other non aggregate columns. On most other databases, and even on MySQL in strict mode, this syntax is not allowed. Also, there is no need to have 2 subqueries here. Rather, just select from the basket table and then assert that matching records do not exist in the other table.

Is there a way to multiply results in SQL?

I am building a website which populates from a database. I'm testing now, and I'd like to see what my site will look like with a lot of data (mainly so I can watch performance, build out pagination, and address any issues with presentation). I have about 10 pieces of data in my table, which is great, but I'd like to display about 2,000 on my page.
Is there a way I can read from the same SELECT * FROM table statement over and over again in the same query in order to read the table multiple times?
I can do this by feeding all my results into a variable and echoing that variable multiple times, but it won't allow me to set a LIMIT or give me the proper count of rows from the query.
I'm surprised I haven't found a way to do this by Googling. It seems like it would be an easy, built-in thing.
If there's not, can you suggest any other way I can do this without modifying my original table?
Please use Cross Join. Cross Join will give you a cartesian product of rows from tables joined. Cross Join can generate a lot of data in quick amount of time. Can be useful for extensive testing.
Example:
SELECT * FROM A
CROSS JOIN B;
You can cross join on the same table as well.
As of MySQL 8 you can use a recursive query to get your rows multifold:
with recursive cte (a, b, c) as
(
select a, b, 1 from mytable
union all
select a, b, c + 1 from cte where c < 10 -- ten times as many
)
select a, b from cte;
(You can of course alter the generated values in the part after union all, e.g.: select a + 5, b * 2, c + 1 from cte where c < 10.)
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=3a2699c167e1f4a7ffbe4e9b17ac7241

MySQL select rows for which no related row exists for each date in a date range

I have a query that selects from one table based on rows in a related table not existing for a particular date. Right now, I call this query several times once with each date I'm interested in. But for performance reasons, I'd like one round trip to the database. I want to expand this query to work over a date range and return all rows in the range where there are not related rows in the other table for each date (ie UNION of results of current query for each date in range). The results must include the date itself in each row. My current query is something like this:
SELECT
t1.id,
t1.field1,
t1.field2,
'2016-03-17' AS nightof_date,
1 as marker
FROM
t1
LEFT JOIN t2 ON (
(t2.a_date = '2016-03-17')
AND (t2.t1_id=t1.id)
AND (some conditions...))
WHERE
(t2.id is NULL)
AND (some other conditions...)
GROUP BY
t1.field3;
Here's a fiddle of a single query:
http://sqlfiddle.com/#!9/553d49/6/0
And here's what I'm trying to achieve as a result for a start date 2016-03-17 and end-date 2016-03-20:
http://sqlfiddle.com/#!9/553d49/6/0
(I suppose I could programmatically generate a monster union query like this but I was hoping for something a bit more elegant where I could just use the start and end dates)
Is there a way to do this without using the NUMBERS or similar trick (ie. I'm hoping not to have to generate a seperate table)?
Does this helps you ?
SELECT
t1.id,
t1.name,
t1.birth,
'2015-01-01 AND 2015-01-03' AS nightof_date
FROM
t1
LEFT JOIN t2 ON (t2.t1_id=t1.id
AND
(t2.birth BETWEEN '2015-01-01' AND '2015-01-03'))
WHERE (t2.id is NULL)
GROUP BY
t1.name;

Why can't I use tuples or ordered pairs in a subquery in MySQL?

Say I want to get the most recent row in a table that has a bunch of records with different IDs.
First, I create a temp table, where I find the most recent rows (grouped by ID of course):
CREATE TEMPORARY TABLE
temp1
AS
SELECT DISTINCT ID, max(date) FROM atable GROUP BY ID;
But, since the whole point was to get all the values for these records, I have to join this back to the original table, atable. Annoying, but what can you do.
I really, really want to use a tuple or an order pair. Why can't I do this in MySQL??
SELECT * FROM atable
WHERE (ID, date) IN
(SELECT ID, date FROM temp1);
What is the canonical syntax to do this?
(Further, philosophical question: Why is MySQL so clunky with this? It's been around decades, and nobody have ever implemented something this basic?)
Why can't I do this in MySQL??
You can, but not with IN. The way to match multiple columns is with EXISTS:
SELECT * FROM atable
WHERE EXISTS
(SELECT NULL FROM temp1
WHERE temp1.ID = atable.ID AND temp1.date = atable.date);
Note that you could also use your original query as a subquery:
SELECT * FROM atable
WHERE date = (SELECT max(date) FROM atable WHERE ID = atable.ID)
Why is MySQL so clunky with this?
The "standard" use of IN is to find records where one value is contained in a list of other values (e.g. WHERE NAME IN ('Smith', 'Jones'). This has been extended to allow a subquery to provide the list rather than a static list.
If you feel that it's a worthy feature for MySQL to implement (and you seem to think it's very easy) then you can submit a feature request, but since 1) there is another way to accomplish it and 2) it would be non-standard SQL I would be surprised if it got a lot of attention.

SQL Server: Selecting DateTime and grouping by Date

This simple SQL problem is giving me a very hard time. Either because I'm seeing the problem the wrong way or because I'm not that familiar with SQL. Or both.
What I'm trying to do: I have a table with several columns and I only need two of them: the datetime when the entry was created and the id of the entry. Note that the hours/minutes/seconds part is important here.
However, I want to group my selection according to the DATE part only. Otherwise all groups will most likely have 1 element.
Here's my query:
SELECT MyDate as DateCr, COUNT(Id) as Occur
FROM MyTable tb WITH(NOLOCK)
GROUP BY CAST(tb.MyDate as Date)
ORDER BY DateCr ASC
However I get the following error from it:
Column "MyTable.MyDate" is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
If I don't do the cast in the GROUP BY, everything fine. If I cast MyDate to DATE in the SELECT and keep the CAST from GROUP BY, everything fine once more. Apparently it wants to keep the same DATE or DATETIME format in the GROUP BY as in the SELECT.
My approach can be completely wrong so I am not necessarily looking to fix the above query, but to find the proper way to do it.
LE: I get the above error on line 1.
LE2: On a second look, my question indeed is not very explicit. You can ignore the above approach if it is completely wrong. Below is a sample scenario
Let me tell you what I need: I want to retrieve (1) the DateTime when each entry was created. So if I have 20 entries, then I want to get 20 DateTimes. Then if I have multiple entries created on the same DAY, I want the number of those entries. For example, let's say I created 3 entries on Monday, 1 on Tuesday and 2 today. Then from my table I need the datetimes of these 6 entries + the number of entries which were created on each day (3 for 19/03/2012, 1 for 20/03/2012 and 2 for 21/03/2012).
I'm not sure why you're objecting to performing the CONVERT in both the SELECT and the GROUP BY. This seems like a perfectly logical way to do this:
SELECT
DateCr = CONVERT(DATE, MyDate),
Occur = COUNT(Id)
FROM dbo.MyTable
GROUP BY CONVERT(DATE, MyDate)
ORDER BY DateCr;
If you want to keep the time portion of MyDate in the SELECT list, why are you bothering to group? Or how do you expect the results to look? You'll have a row for every individual date/time value, where the grouping seems to indicate you want a row for each day. Maybe you could clarify what you want with some sample data and example desired results.
Also, why are you using NOLOCK? Are you willing to trade accuracy for a haphazard turbo button?
EDIT adding a version for the mixed requirements:
;WITH d(DateCr,d,Id) AS
(
SELECT MyDate, d = CONVERT(DATE, MyDate), Id
FROM dbo.MyTable)
SELECT DateCr, Occur = (SELECT COUNT(Id) FROM d AS d2 WHERE d2.d = d.d)
FROM d
ORDER BY DateCr;
Even though this is an old post, I thought I would answer it. The solution below will work with SQL Server 2008 and above. It uses the over clause, so that the individual lines will be returned, but will also count the rows grouped by the date (without time).
SELECT MyDate as DateCr,
COUNT(Id) OVER(PARTITION BY CAST(tb.MyDate as Date)) as Occur
FROM MyTable tb WITH(NOLOCK)
ORDER BY DateCr ASC
Darren White