Change results in mysql query - mysql

I would like to manipulate the result I get from a query.
I have a set of 2.5m rows and there are 10 different ID's for a status. These statusses are not mapped in another table but I would like to manipulate the result I get in SQLyog.
What I would like to do is:
Count(Id) | Status
------------------
500.000 | 1
750.000 | 2
convert into a result
Count(Id) | Status
-------------------
500.000 | Initial order
750.000 | Cancelled
Can this be done in the query? Note that I'm not using PHP or a browser to display the results.

select
count(*) as TotalRecs,
case status
when 1 then "Initial Order"
when 2 then "Cancelled "
when 3 then "whatever "
else "all others "
end case as WordStatus
from
YourTable
group by
2

You can either inline it in a case statement
select COUNT(id),
case status
when 1 then 'initial order'
when 2 then 'cancelled'
# without an else, the rest go to NULL
end status
from tbl
group by status # yes, just on status
Or I would strongly encourage you to create a reference table for this
Tbl Status contains 2 columns ID and Description
select COUNT(tbl.id), status.description
from tbl
LEFT join status on status.id = tbl.status
group by status.description

Related

MySQL query to gather incorrectly stored data

I have recently taken over a email campaign project and need to generate a report for the customer. However the data has been stored very strangely.
Basically the client wants a report of the subscribers first name and last name that have subscribed to a emailing list.
Example table data.
------------------------------------------------------------
id | owner_id | list_id | field_id | email_address | value
------------------------------------------------------------
1 10 1 137 me#example.com John
2 10 1 138 me#example.com Doe
So as you can see, John Doe has subscribed to mailing list 1, and field_id 137 is his first name and field_id 138 is his last name.
The client is looking for a export with the users first name and last name all is one field.
I tred the following sql query
SELECT value
FROM Table_A AS child
INNER JOIN Table_A AS parent
ON parent.email_address = child.email_address
WHERE child.owner_id = '10'
But unfortunately the query gives me the results in many rows but not appending the first name and last name into one field,
If anyone can provide some assistance that would be awesome.
Thanks.
SELECT
concat( parent.value,' ',child.value)name
FROM mytable AS child
left JOIN mytable AS parent
ON parent.email_address = child.email_address
WHERE child.owner_id = '10'
and parent.field_id=137 and child.field_id=138
Check at-http://sqlfiddle.com/#!9/199b4b/45
I think you have to use a variable to put in there everything you have to and then select the variable with the desired name of yours.
For example:
DECLARE #yourvariable VARCHAR(MAX)
SELECT #yourvariable = COALESCE(#yourvariable + " ") + value
FROM table_A
WHERE owner_id = 10
SELECT #yourvariable as FullName
Try that, it might help.
You can try this code(column name equals value in your original DB):
select a.name
from
table_a a inner join table_a b
on a.email_address = b.email_address and a.field_id <> b.field_id
where a.owner_id=10
order by a.field_id
Here is the example link:
http://sqlfiddle.com/#!9/5fbdf6/25/0
As per assumptions, first name has the field id 137 and last name has the field id 138.
You can try the following query to get the desired result.
SELECT CONCAT(SUBSTRING_INDEX(GROUP_CONCAT(`value`),",",1)," ",SUBSTRING_INDEX(GROUP_CONCAT(`value`),",",-1)) AS client_name
FROM Table_A
WHERE owner_id = 10
AND field_id IN (137, 138)
GROUP BY email_address;

Selecting rows until a column value isn't the same

SELECT product.productID
, product.Name
, product.date
, product.status
FROM product
INNER JOIN shelf ON product.sheldID=shelf.shelfID
WHERE product.weekID = $ID
AND product.date < '$day'
OR (product.date = '$day' AND shelf.expire <= '$time' )
ORDER BY concat(product.date,shelf.expire)
I am trying to stop the SQL statement at a specific value e.g. bad.
I have tried using max-date, but am finding it hard as am making the time stamp in the query. (Combining date/time)
This example table shows that 3 results should be returned and if the status "bad" was the first result than no results should be returned. (They are ordered by date and time).
ProductID Date status
1 2017-03-27 Good
2 2017-03-27 Good
3 2017-03-26 Good
4 2017-03-25 Bad
5 2017-03-25 Good
Think I may have fixed it, I added this to my while loop.
The query gives the results in order by present to past using date and time, this while loop checks if the column of that row is equal to 'bad' if it is does something (might be able to use an array to fill it up with data). If not than the loop is broken.
I know it doesn't seem ideal but it works lol
while ($row = mysqli_fetch_assoc($result)) {
if ($row['status'] == "bad") {
$counter += 1;
}
else{
break;}
I will provide an answer just with your output as if it was just one table. It will give you the main ideia in how to solve your problem.
Basically I created a column called ord that will work as a row_number (MySql doesn't support it yet AFAIK). Then I got the minimum ord value for a bad status then I get everything from the data where ord is less than that.
select y.*
from (select ProductID, dt, status, #rw:=#rw+1 ord
from product, (select #rw:=0) a
order by dt desc) y
where y.ord < (select min(ord) ord
from (select ProductID, status, #rin:=#rin+1 ord
from product, (select #rin:=0) a
order by dt desc) x
where status = 'Bad');
Result will be:
ProductID dt status ord
-------------------------------------
1 2017-03-27 Good 1
2 2017-03-27 Good 2
3 2017-03-26 Good 3
Also tested with the use case where the Bad status is the first result, no results will be returned.
See it working here: http://sqlfiddle.com/#!9/28dda/1

Setting priority in SQL

We have a table test in which we have status_cd as one of the column. Status Code can have three value - Prelim, Approved and confirmed.
I have to write a query in such a way that it should fetch the record for confirmed status cd. If confirmed status cd is not present, then fetch for Approved, if approved is not present, fetch for prelim, if prelim is also not present, fetch for null
id rule_id status_cd
1 1 prelim
2 1 null
3 1 approved
in above example, the query should return approved for rule_id=1
Try this way:
SELECT T1.*
FROM test T1 JOIN
(SELECT *,CASE status_cd WHEN 'confirmed' THEN 1
WHEN 'approved' THEN 2
WHEN 'prelim' THEN 3
ELSE 4 END AS Rank
FROM test) T2 ON T1.id=T2.id AND T1.Rule_id =T2.Rule_id
ORDER BY T2.Rank
LIMIT 1
Result:
ID RULE_ID STATUS_CD
3 1 approved
Sample result in SQL Fiddle.
Use the values '3 Confirmed','2 Approved', '1 Prelim' and '0 Null' or just use a default value of zero in a numerical field and set the value to 1, 2, 3 as the rule progresses (much faster execution, but avoid the null either way by using a default value of '0 Null' in the field if you keep a string implementation).
Then fetch the records with this query:
SELECT status_cd FROM YourTableName WHERE rule_id=1 ORDER BY status_cd DESC;
The first row of the query will always contain the answer you want. Additionally, the other rows will be there to confirm that all the other steps were present, etc. if you want to look at those rows too. If you know you only need the one row, then use
SELECT TOP 1 status_cd FROM ... (the rest is the same)

How to make a select that returns 4 totals from same table but with different filters

I'm trying to make a report in SSRS where I show some totals from the same table. I know I can use selects into select, but I've heard that could affect the performance and make it slow. That is why I decided to use store procedures but I'm not so familiar with it (I only did some basic SP) so some help will be apreciated:
This is what I need to get:
|--------------|------------------------- TOTALS AND PERCENTAGES ----------------------|
|COMPANY | PACKAGES | WEIGHT | PACKAGE_DELIVERED |% DELIVERED | ONTIME |% ONTIME |
These are the querys I did in a previous version of the report (using asp):
SELECT COMPANY_NAME, COUNT(ID) AS PACKAGES, SUM(WEIGHT) AS WEIGHT
FROM PACKAGE
WHERE ACTUAL_DELIVERY_DATE BETWEEN 'X' AND 'Y'
GROUP BY COMPANY_CODE, COMPANY_NAME
Then I put the results in arrays and then make a new select to get the rest of information adding the COMPANY as filter:
SELECT COMPANY_CODE, ESTIMATED_DELIVERY_DATE, ACTUAL_DELIVERY_DATE
FROM PACKAGE
WHERE ACTUAL_DELIVERY_DATE BETWEEN 'X' AND 'Y'
AND STATUS = 'DELIVERED'
AND COMPANY_CODE = 'DHL'
ORDER BY STATUS
For every row
PACKAGES_DELIVERED = + 1
IF ACTUAL_DELIVERY_DATE < ESTIMATED_DELIVERY_DATE THEN ONTIME = + 1
Next
Then I calculate the percentages and show all together in a table.
Somebody that can help me to put all this in a Store Procedure or maybe have another idea.
Thanks in advance.
I would add the following columns to the original SELECT, using SUM on a CASE statement:
, SUM ( CASE WHEN STATUS = 'DELIVERED' THEN 1 ELSE 0 END ) AS PACKAGES_DELIVERED
, SUM ( CASE WHEN STATUS = 'DELIVERED' AND ACTUAL_DELIVERY_DATE < ESTIMATED_DELIVERY_DATE THEN 1 ELSE 0 END ) AS ONTIME
This doesnt seem complex enough to bother with a Stored Procedure.

UPDATE query using record counts (DCount) from another table

Anyone please help me to solve this query?
I have two tables one table(Act_Tkt) contain fields like below
PName | Severity1 | Severity2
_____________________________
AAAA | |
Another table (Data) has some fields like below
PName | Severity | Type | Group | Create_Date
_____________________________________________
Now i need to update the count of records from (Data) to Act_Tkt with below criteria for that particular PName
UPDATE Act_Tkt INNER JOIN Data ON Act_Ticket.PName = Data.PName
SET Severity1 =
=DCount("[PName]","Data","[Severity] = 'S1' and [Type] <> 'R' and [Group] <> 'Support' and [Create_Date]< #11/14/2013 16:00:00#")
I have used the above query but i am getting same number in all the rows in Act_Tkt.
Any advise will be much appreciated.
Thanks in advance.
If you're using DCount() then you don't need to do the INNER JOIN on [Data]. What you do need is something in the DCount() criteria that relates back to the current [Act_Tkt] row. (Currently your DCount() criteria string never changes from one row to the next, which is why you get the same value for every row.)
Try this instead:
UPDATE Act_Tkt
SET Severity1 = DCount("*","Data","[Severity] = 'S1' and [Type] <> 'R' and [Group] <> 'Support' and [Create_Date]< #11/14/2013 16:00:00# and [PName]='" & [PName] & "'")