mysql: column values as column name in select result - mysql

i have a table which i group by one column and then i output the different values and the count of this values.
activty | sum
-------------
Form | 1
Login | 4
Reg | 3
here is an example-code: http://sqlfiddle.com/#!2/c6faf/2/0
but i want the different values tp the column names with one row of values (the count).
like this:
Form | Login | Reg
------------------
1 | 4 | 3
i tried the PIVOT operation, but i'm not getting it working. what am i doing wrong?
here is my code: http://sqlfiddle.com/#!2/c6faf/35/0
thanks in advance!
br

Here you go
SELECT
MAX(CASE activity WHEN 'Form' THEN mysum ELSE NULL END) AS Form,
MAX(CASE activity WHEN 'Login' THEN mysum ELSE NULL END) AS Login,
MAX(CASE activity WHEN 'Reg' THEN mysum ELSE NULL END) AS Reg
FROM (
SELECT activity, COUNT(activity) AS mysum FROM tbl_tracking
WHERE id = 141 AND variant = 2
GROUP BY activity
)sq
But in my opinion such formatting should be done in application layer, not in database layer.

Try this:
SELECT
SUM(IF(activity = 'Form',1,0)) as 'Form',
SUM(IF(activity = 'Login',1,0)) as 'Login',
SUM(IF(activity = 'Reg',1,0)) as 'Reg'
FROM
tbl_tracking
WHERE
id = 141
AND variant = 2
Sql Fiddle here

For this you need to use pivot table concept. here you go for same.
SELECT
SUM((IF(activity='Form',1,0))) as Form,
SUM((IF(activity='Login',1,0))) as Login,
SUM((IF(activity='Reg',1,0))) as Reg
FROM
tbl_tracking
WHERE
id = 141
AND
variant = 2;
fiddle

Related

Stuck creating a 0/1 flag that works correctly. Finally giving in

Evening all.
I am trying to create a very basic case statement which buckets three scenarios with a 0 or a 1 in mySQL.
I have three fields found in the reference table link below.
Essentially I am trying to bucket any ProductID that has a StatusCD of 'I' and 'O' as 1, only 'I' as 1 and then anything with only an 'O' result and no corresponding 'I' as a 0. What this data is showing is a product coming into the warehouse ('I') and then exiting the warehouse ('O'). I have other fields which are capturing date differences but ultimately I am trying to create a flag to ignore scenarios where we only have Product#'s with an 'O' statusCD which would indicate their arrival to the warehouse was not logged appropriately and would skew our "Age in warehouse" buckets.
Any insight is greatly appreciated!
Reference Table with fields:
Date | ProductID | StatusCD
2021-01-01 | U1000 | I
2021-01-10 | U1000 | O
2021-01-10 | U2000 | I
2021-01-15 | U3000 | O
Assuming you want to retain every original record, you could use analytic functions here:
SELECT Date, ProductID, StatusCD,
CASE WHEN SUM(StatusCD <> 'O') OVER (PARTITION BY ProductID) = 0
THEN 0 ELSE 1 END As Label
FROM yourTable
ORDER BY Date;
Demo
For versions of MySQL earlier than 8+:
SELECT t1.Date, t1.ProductID, t1.StatusCD,
CASE WHEN t2.OpenCount = 0 THEN 0 ELSE 1 END AS Label
FROM yourTable t1
INNER JOIN
(
SELECT ProductID, SUM(StatusCD <> 'O') AS OpenCount
FROM yourTable
GROUP BY ProductID
) t2
ON t2.ProductID = t1.ProductID
ORDER BY
t1.Date;
Demo

Mysql check empty rows of child elements

I have a query to select all childs (positions) based ob the parent id (order_id):
SELECT * FROM positions WHERE order_id = X
The result looks like:
ID | order_id | checked_1 | checked_2
1 | 1 | J. Doe | M. Doe
2 | 1 | | Mr. Tester
3 | 1 | J. Joe |
Now i need a query to check if the fields checked_1 & checked_2 are not empty of all related childs. So if all fields of the childs are filled, there shoulbe be appear a success notice in frontend.
What is the best way to "migrate" all childs, so that i can afterwards create the php query?
May try this to count if empty value is there:
SELECT count(*) AS count_empty FROM positions
WHERE order_id = X AND (IFNULL(checked_1, '') = '' OR
IFNULL(checked_2, '') = '')
So now, if count_empty is zero you may show the success message.
Try this:
SELECT 'SUCCESS' as '' FROM postions WHERES orderid = x AND (checked_1 IS NOT NULL OR checked_1 = '') AND (checked_2 IS NOT NULL OR checked_2 = '');
We can aggregate here by order, and then check for the presence of an empty checked_1 or checked_2 column, for a given order_id group. You may try the following query:
SELECT
order_id,
CASE WHEN SUM(CASE WHEN COALESCE(checked_1, '') = '' THEN 1 ELSE 0 END) +
SUM(CASE WHEN COALESCE(checked_2, '') = '' THEN 1 ELSE 0 END) = 0
THEN 'valid' ELSE 'invalid' END AS status
FROM positions
WHERE order_id = 1
GROUP BY order_id;
Note that I don't know if the missing values are NULL or actually just empty string. My query covers for both possibilities, but if these missing values be NULL then you can remove my calls to COALESCE. Also, you may remove GROUP BY if you plan on only running this query for a single order_id. Though should you have the need to run the query for multiple orders at a time, what I wrote above should come in handy.
one way to do this:
select MIN(CASE WHEN checked_1 = '' OR checked_2 = '' THEN 0 ELSE 1 END) from positions group by order_id
You will get a '0' if any field is empty or '1' if all are <> ''.
http://sqlfiddle.com/#!9/f7518d/1

SQL Query to compare two values which are in the same column but returned by two different set of queries

I have a table similar to the one shown below.
-----------------------------
JOB ID | parameter | result |
-----------------------------
1 | xyz | 10 |
1 | abc | 15 |
2 | xyz | 12 |
2 | abc | 8 |
2 | mno | 20 |
-----------------------------
I want the result as shown below.
parameter | result 1 | result 2 |
----------------------------------
xyz | 10 | 12 |
mno | NULL | 20 |
abc | 15 | 8 |
----------------------------------
My goal is to have a single table which can compare the result values of two different jobs. It can be two or more jobs.
you want to simulate a pivot table since mysql doesn't have pivots.
select
param,
max(case when id = 1 then res else null end) as 'result 1',
max(case when id = 2 then res else null end) as 'result 2'
from table
group by param
SQL FIDDLE TO PLAY WITH
If you are using MySQL there are no "outer join" need to use union right and left join:
Something like:
select t1.parameter, t1.result 'Result 1', t2.result 'Result 2' from
table as t1 left join table as t2
on t1.parameter=t2.parameter
where t1.'JOB ID' = 1 and t2.'JOB ID' = 2
union
select t1.parameter, t1.result 'Result 1', t2.result 'Result 2' from
table as t1 right join table as t2
on t1.parameter=t2.parameter
where t1.'JOB ID' = 1 and t2.'JOB ID' = 2
If the SQL with full outer join will make it more easier:
select t1.parameter, t1.result 'Result 1', t2.result 'Result 2' from
table as t1 outer join table as t2
on t1.parameter=t2.parameter
where t1.'JOB ID' = 1 and t2.'JOB ID' = 2
In Postgres, you can use something like:
select parameter, (array_agg(result))[1], (array_agg(result))[2] from my_table group by parameter;
The idea is: aggregate all the results for a given parameter into an array of results, and then fetch individual elements from those arrays.
I think that you can achieve something similar in MySQL by using GROUP_CONCAT(), although it returns a string instead of an array, so you cannot easily index it. But you can split by commas after that.
select q1.parameter, q2.result as r1, q3.result as r2
from
(select distinct parameter from temp2) q1
left join (select parameter, result from temp2 where job_id = 1) q2
on q1.parameter = q2.parameter
left join (select parameter, result from temp2 where job_id = 2) q3
on q1.parameter = q3.parameter;
It works, but it's not efficient. Still, since I'm gathering you are trying to solve something more complex than what's presented, this might help form your general solution.
While I'm at it, here's a slightly cleaner solution:
select distinct q1.parameter, q2.result as r1, q3.result as r2
from
temp2 q1
left join (select parameter, result from temp2 where job_id = 1) q2
on q1.parameter = q2.parameter
left join (select parameter, result from temp2 where job_id = 2) q3
on q1.parameter = q3.parameter;

Group by, converting rows to columns with no aggregate

I need to group the table during my query, and up until know I was doing that after querying - with the code as my group is quite complicated. But with the new data it appears to take minutes, and I'm thinking is there better way.
My current query results in this:
FKId | Name | A | B | C
1 Alpha 2 3 2
1 Beta 2 5 7
2 Alpha 8 1 10
2 Beta 7 -5 6
2 Gamma 1 2 3
And I convert it to this:
FKId | Alpha[A] | Alpha[B] | Alpha[C] | Beta[A] | Beta[B] | Beta[C] | Gamma[A] | Gamma[B] | Gamma[C]
1 2 3 2 2 5 7
2 8 1 10 7 -5 6 1 2 3
Is it possible to do with SQL? (and I assume it should be much faster than if I do this with code)
The names can be anything
I have very big number of colums A, B, C (like 20 - 30). The number of result columns can easily go to thousands as average project has about 100 names.
I have like 10-20 columns that I should group by, but doing a single group by FKId is fine - these columns are the same.
We use different SQL DBs, so I cannot use specific functions like PIVOT. I know that we used MySQL, MsSQL and SQLite a lot
We use NHibernate if it makes any difference.
I would also honor the solution done for MySQL if specific functions are used. We use it in 80% and it will already greatly improve the average performance if I could do that at least for MySQL.
Basically, you want to transpose the data. Here is what you can try. It should work across all databases but you need to know the columns A, B, C, etc beforehand:
create table my_table (
fkid integer,
name varchar(10),
a integer,
b integer,
c integer
);
insert into my_table values(1,'alpha',2,3,2)
,(1,'beta',2,5,7)
,(2,'alpha',8,1,10)
,(2,'beta',7,-5,6)
,(2,'gamma',1,2,3);
select fkid
, max(case when name = 'alpha' then a else null end) as alphaa
, max(case when name = 'alpha' then b else null end) as alphab
, max(case when name = 'alpha' then c else null end) as alphac
, max(case when name = 'beta' then a else null end) as betaa
, max(case when name = 'beta' then b else null end) as betab
, max(case when name = 'beta' then c else null end) as betac
, max(case when name = 'gamma' then a else null end) as gammaa
, max(case when name = 'gamma' then b else null end) as gammab
, max(case when name = 'gamma' then c else null end) as gammac
from my_table
group by fkid;

Counting partial values or conditional values

I hope someone can lend an assist and some advise here. I'm trying to get a fairly complex result and not sure if I can do it as one query with subqueries, a union, or simply separate queries to be merged into excel after the fact.
I'm working with a legacy database from my predecessor with the following tables:
Business (columns working with: id, sector, state)
Forms (columns working with: Submitted (Y/N), id, business_id)
Inventory (Columns working with: In_stock (Y/N), id, form_id)
I'm trying to get a final result that looks like this:
| SubmittedForms | Unsubmitted Forms | Sector | State |
|-----------------------------------------------------|
| 10 | 5 | Agr | UT |
| 0 | 7 | Chem | MT |
| 2 | 1 | Bio | OK |
| 13 | 0 | Chem | NM |
The main problem I'm getting is that while submitted forms doesn't need any further arguments and is a simple count, the unsubmitted forms are dependent on the Inventory.in_stock='Y'. Here's my query for the submitted forms:
SELECT COUNT(Forms.id) AS Submitted, Business.sector, Business.state
FROM Forms
JOIN Business ON Forms.business_id=Business.id
WHERE Forms.submitted='Y'
GROUP BY Business.state, Business.sector
Unfortunately, I can't seem to get the unsubmitted forms number to calculate correctly. It just returns the total count of rows where in_stock is Y for that sector.
If it's easier to run a separate query for Submitted and Unsubmitted that's fine for the end result but I need some help getting the correct count of Unsubmitted forms with the in_stock flagged as Y. Also, I attempted to use a COUNT DISTINCT but takes way too long, was still running after 10 minutes. Another complication I can envision in a single query option is the possibility of 0/null values in either Submitted or Unsubmitted forms
Any help is greatly appreciated!
One option:
SELECT COUNT(CASE WHEN Forms.submitted = 'Y' THEN 1 END) SubmittedForms,
COUNT
( CASE WHEN Forms.submitted = 'N'
AND EXISTS ( SELECT 1
FROM Inventory
WHERE form_id = Forms.id
AND in_stock = 'Y'
)
THEN 1
END
) UnsubmittedForms,
Business.sector Sector,
Business.state State
FROM Forms
RIGHT
OUTER
JOIN Business
ON Forms.business_id = Business.id
GROUP
BY Business.sector,
Business.state
;
Another option, which might perform better:
SELECT COUNT(CASE WHEN Forms.submitted = 'Y' THEN 1 END) SubmittedForms,
COUNT(CASE WHEN Forms.submitted = 'N' THEN 1 END) UnsubmittedForms,
Business.sector Sector,
Business.state State
FROM ( SELECT *
FROM Forms
WHERE submitted = 'Y'
OR id IN ( SELECT DISTINCT form_id
FROM Inventory
AND in_stock = 'Y'
)
) Forms
RIGHT
OUTER
JOIN Business
ON Forms.business_id = Business.id
GROUP
BY Business.sector,
Business.state
;