SELECT IF THEN ELSE statement - mysql

I want to do query like this
SELECT if(EXISTS(SELECT * FROM application WHERE id_student=1
AND ap_status<>"Wysłano" AND date(app_date) > (SELECT tax_year FROM const_data)),
(SELECT * FROM application WHERE id_student=1 AND ap_status<>"Wysłano" AND date(app_date) > (SELECT tax_year FROM const_data)),
(SELECT * FROM application WHERE id_student=1 AND date(app_date) > (SELECT tax_year FROM const_data)))
But true or false value should contain one column. Is it possible, to make this in other way?

I'm not even sure if what you tried would execute, but this should accomplish what that looks like it is trying to:
SELECT *
FROM application
WHERE id_student=1 AND date(app_date) > (SELECT tax_year FROM const_data)
ORDER BY ap_status="Wysłano"
LIMIT 1
This will fail if const_data has more than one row though.
Edit: Hmm, this answer is not quite right if you expect multiple records. At this point, the best solution is to remove the limit and handle the results in whatever code processes these results. It CAN be done in a single query, but I generally wouldn't recommend it.
Edit2: Sidenote... if app_date is a datetime, you may see performance boosts by removing the use of the DATE() function and instead converting tax_year to a datetime.
Edit3: Last one, I promise.... probably. In the case where it must be done in one query, and results cannot be processed after, this should work.
SELECT *
FROM application
WHERE id_student=1 AND date(app_date) > (SELECT tax_year FROM const_data)
AND IF(EXISTS([that query]), ap_status<>"Wysłano", TRUE)

Related

Multiple new variable in mysql query

My problem is simple, I'm using the query
(ReturnItm.PackQty * ReturnItm.ReturnQty) as Total_Qty,
CASE
WHEN ReturnItm.UOM='U' THEN
IF(Inventory.Price=0,Inventory.Pricec,Inventory.Price)
WHEN ReturnItm.UOM='P' THEN Inventory.Pricep
ELSE Inventory.Pricec
END AS Price
So, how to multiple that Total_Qty and Price?
Is it just like this?
(Total_Qty*Price) as Total_price
Help me, please
To select this product in the same select clause, you'll have to repeat the full expressions:
SELECT
Test.1,
Test.2,
Test.3,
Test.4,
(Test.1 * Test.2) AS TestNew1,
(Test.3 * Test.4) AS TestNew2,
Test.1 * Test.2 * Test.3 * Test.4 AS TotalTest
FROM Test;
Use a sub-query...
SELECT
*,
(TestNew1 * TestNew2) as TotalTest
FROM
(
SELECT
Test.1,
Test.2,
Test.3,
Test.4,
(Test.1 * Test.2) as TestNew1,
(Test.3 * Test.4) as TestNew2
FROM
Test
)
AS x
The inner query acts as a scope within which the new columns can be expressed, and the outer query acts as a scope where there can be referrenced.
Also, in terms of performance, note that SQL isn't executed as written. It's a "declarative" language; it's a means of expressing the functionality, and then the DBMS turns than in to an actual execution plan.

Why is this MySQL statement pulling data from both tables on this JOIN?

select * from user_levels
join collectors_users on user_levels.id = collectors_users.user_level
where collectors_users.username = 'testuser'
I want it to pull everything from user_levels and nothing from collectors_users. But it's pulling from both. How do I correct the statement?
Instead of select * specify what you actually want and use select user_levels.* or even better skip the * and write out the columns you want (and consider using aliases to keep it short and tidy): select ul.col1, ul.col2 ... from userlevels ul join ...
It is getting all the data as the '*' means 'all' columns. You can limit the columns for just one table by specifying the table:
select user_levels.*
from user_levels
join collectors_users on user_levels.id = collectors_users.user_level
where collectors_users.username = 'testuser'
Pro tip: Don't use SELECT * in running software. Instead, be as specific as you can be about the columns you want in your result set.
SELECT user_levels.*
should help a bit.
I might suggest that you use in or exists, because this is more consistent with the intention of the query:
select ul.*
from user_levels ul
where ul.id in (select cu.user_level
from collectors_users cu
where cu.username = 'testuser'
);
In addition, this version will not produce duplicate rows if collectors_users has multiple matching rows for a singel row in user_levels.
Also note the use of table aliases: these make the query easier to write and to read.

Finding duplicates, which shares a common property

I’m trying to select duplicated nodes on a Drupal site, basically i need to select nodes that share a common ‘tnid' (translation node id), and also share the same ‘language’.
But i can’t figure out how to write the query, i think i did the first part, finding nodes with common tnid, like so
SELECT origin.nid, origin.tnid, origin.title, origin.language
FROM node AS origin
JOIN (select nid, tnid from node
group by tnid having count(tnid) > 1) common_tnid ON common_tnid.tnid = origin.tnid
#JOIN node common_lang ON common_lang.language = origin.language
AND common_lang.tnid = origin.tnid
WHERE origin.tnid != 0
Considering the language part is my big hurdle, how would i add that to the query? I tried a bunch of stuff, thus. the comment.
Try this:
SELECT
table1.nid nid,
table1.tnid tnid,
table1.language language,
table1.title title
FROM
(
SELECT *
FROM
table1
GROUP BY
tnid, language
HAVING
COUNT(*) > 1
) dupe
LEFT JOIN
table1
ON dupe.tnid = table1.tnid
AND dupe.language = table1.language
SQL Fiddle: http://sqlfiddle.com/#!9/294cc/1/0
You can try something like this
SELECT origin.id AS origin_id, common.id AS common_id
FROM node AS origin
INNER JOIN node AS common ON common.language = origin.language AND common.tnid = origin.tnid AND origin.id != common.id
I dont know if your table has id field but you can change to some field that is different in both rows

Reset a running total if field value is hit

I am able to keep a running total with the below query, and it does that just fine. What I really want, is when the gap field is greater than or equal to the date_diff field, the running total should reset back to the current hrly_qty. I'm sure I could achieve my results with a cursor, but I wanted to know of possible other ways. Ideas?
Example:
WITH CTE AS
(
SELECT a.*, SUM(b.hrly_qty) AS running_total, c.gap
FROM #tmpTrxhist2 a
INNER JOIN #tmpTrxhist2 b ON a.people_id = b.people_id
AND b.sequence_id <= a.sequence_id
INNER JOIN incent_level c ON a.owner_division_id = c.owner_division_id
GROUP BY a.date_diff, a.owner_division_id, a.people_id, a.sequence_id,
a.hrly_qty, c.gap
)
SELECT * FROM CTE
ORDER BY people_id, sequence_id
You seldom need a cursor! A simple case statement should suffice. Of the top of my head something like:
WITH CTE AS
(
SELECT a.*, SUM(b.hrly_qty) AS running_total, c.gap
FROM #tmpTrxhist2 a
INNER JOIN #tmpTrxhist2 b ON a.people_id = b.people_id
AND b.sequence_id <= a.sequence_id
INNER JOIN incent_level c ON a.owner_division_id = c.owner_division_id
GROUP BY a.date_diff, a.owner_division_id, a.people_id, a.sequence_id,
a.hrly_qty, c.gap
)
SELECT *,
CASE
WHEN gap >= date_diff then hrly_qty else gap
END as comp_gap
FROM CTE
ORDER BY people_id, sequence_id
Run the execution plans between the two but SQL is almost always much happier trying to optimise non-cursored code. In my field at least, you usually find cursors are over used and abused by 'proper' C/C++ programmers because they get in their comfort zone when see something that looks a bit like a while-loop rather than think about sets of data. There is a place for cursors, but this isn't it!

MYSQL GROUP_CONCAT and IN

I have a little query, it goes like this:
It's slightly more complex than it looks, the only issue is using the output of one subquery as the parameter for an IN clause to generate another. It works to some degree - but it only provides the results from the first id in the "IN" clause. Oddly, if I manually insert the record ids "00003,00004,00005" it does give the proper results.
What I am seeking to do is get second level many to many relationship - basically tour_stops have items, which in turn have images. I am trying to get all the images from all the items to be in a JSON string as 'item_images'. As stated, it runs quickly, but only returns the images from the first related item.
SELECT DISTINCT
tour_stops.record_id,
(SELECT
GROUP_CONCAT( item.record_id ) AS in_item_ids
FROM tour_stop_item
LEFT OUTER JOIN item
ON item.record_id = tour_stop_item.item_id
WHERE tour_stop_item.tour_stops_id = tour_stops.record_id
GROUP BY tour_stops.record_id
) AS rel_items,
(SELECT
CONCAT('[ ',
GROUP_CONCAT(
CONCAT('{ \"record_id\" : \"',record_id,'\",
\"photo_credit\" : \"',photo_credit,'\" }')
)
,' ]')
FROM images
WHERE
images.attached_to IN(rel_items) AND
images.attached_table = 'item'
ORDER BY img_order ASC) AS item_images
FROM tour_stops
WHERE
tour_stops.attached_to_tour = $record_id
ORDER BY tour_stops.stop_order ASC
Both of these below answers I tried, but it did not help. The second example (placing the entire first subquery inside he "IN" statement) not only produced the same results I am already getting, but also increased query time exponentially.
EDIT: I replaced my IN statement with
IN(SELECT item_id FROM tour_stop_item WHERE tour_stops_id = tour_stops.record_id)
and it works, but it brutally slow now. Assuming I have everything indexed correctly, is this the best way to do it?
using group_concat in PHPMYADMIN will show the result as [BLOB - 3B]
GROUP_CONCAT in IN Subquery
Any insights are appreciated. Thanks
I am surprised that you can use rel_items in the subquery.
You might try:
concat(',', images.attached_to, ',') like concat('%,', rel_items, ',%') and
This may or may not be faster. The original version was fast presumably because there are no matches.
Or, you can try to change your in clause. Sometimes, these are poorly optimized:
exists (select 1
from tour_stop_item
where tour_stops_id = tour_stops.record_id and images.attached_to = item_id
)
And then be sure you have an index on tour_stop_item(tour_stops_id, item_id).