Making a query with two columns computed from data in one column - sql

I just started checking SQL server in my work, and I just canĀ“t manage to solve this very easy thing.
Lets say I have this Table:
Model Serial Pass Failure
Y72742 LURC1 0 Ref 5
Y72742 LURC2 0 Ref 10
Y72596 JDID1 1 EMT
Y72596 JDID2 1 EMT
Y72742 LURC3 0 Ref 10
Y72596 JDID3 0 Ref 5
Y72596 JDID4 0 Ref 18
Y72596 JDID5 1 EMT
Y72596 JDID6 0 Ref 18
Y72596 JDID7 0 Ref 5
Y72596 LURC4 1 UMT
Y72596 LURC5 1 UMT
So in the PASS column, the 1 means the unit passed, the 0 means it failed. The Failure Column indicates what was the failure.
I'm trying to accomplish something like this:
Model Pass Failed Percentage
Y72742 2 3 40%
Y72596 1 4 20%
But since is the same column I just can't get it done.
I tried with a subquery with the "AND" operator, but I got errors. if anyone could help me I would be very grateful.
Regards.

You can construct your query using SUM and GROUP BY:
SELECT
Model
, SUM(case when Pass=1 then 1.0 else 0.0 end) AS Pass
, SUM(case when Pass=1 then 0.0 else 1.0 end) AS Failed
, 100*SUM(case when Pass=1 then 1.0 else 0.0 end)/COUNT(*) AS Percentage
FROM MyTable
GROUP BY Model

MySQL implementation:
SELECT
t.Model,
SUM(IF(t.Pass=1,1,0)) as Passed,
SUM(IF(t.Pass=0,1,0)) as Failed,
SUM(IF(t.Pass=1,1,0))/COUNT(t.Pass) as Percentage
FROM MyTable t
GROUP BY t.Model

Related

How can I solve my question in SQL without using a JOIN?

Data : Desired result:
class type number class rate score
------------------------- ----------------------
2021 1 5 2021 0.5 4.8
2021 1 4.6 2022 0.5 4.6
2021 0 4.8
2021 null null
2022 1 4.2
2022 1 5
2022 0 4.2
2022 null null
rate = (type = 1 / all list) group by class.
score = AVG(number) where type = 1 group by class.
I want to do like below:
SELECT
a.class, SUM(type) / COUNT(*) AS rate, b.score
FROM
data as a
LEFT JOIN
(SELECT
class, AVG(number) AS score
FROM
data
WHERE
type = 1
GROUP BY
class) AS b ON a.class = b.class
GROUP BY
class
Is there any method to do this without JOIN?
First some issues should be named:
Do not use SQL key words like type or number as column names or table names.
Do not do a division without ruling out possible dividing by zero exceptions.
Anyway, in case your description is correct, you can do following:
SELECT class,
ROUND(AVG(CAST(COALESCE(type,0) AS FLOAT)),2) AS rate,
ROUND(AVG(CASE WHEN type = 1 THEN COALESCE(number,0) END),2) AS score
FROM data
GROUP BY class;
You can see here it's working correctly: db<>fiddle
Some explanations:
AVG will build the average without doing risky divisions.
COALESCE replaces NULL values by zero to make sure the average will be correct.
ROUND makes sure the average will be shown as example as 0.33, not as 0.33333...
If this is not sufficient for you, please be more precise about what exactly you want to do.

Converting Column Headers to Row elements

I have 2 tables I am combining and that works but I think I designed the second table wrong as I have a column for each item of what really is a multiple choice question. The query is this:
select Count(n.ID) as MemCount, u.Pay1Click, u.PayMailCC, u.PayMailCheck, u.PayPhoneACH, u.PayPhoneCC, u.PayWuFoo
from name as n inner join
UD_Demo_ORG as u on n.ID = u.ID
where n.MEMBER_TYPE like 'ORG_%' and n.CATEGORY not like '%_2' and
(u.Pay1Click = '1' or u.PayMailCC = '1' or u.PayMailCheck = '1' or u.PayPhoneACH = '1' or u.PayPhoneCC = '1' or u.PayWuFoo = '1')
group by u.Pay1Click, u.PayMailCC, u.PayMailCheck, u.PayPhoneACH, u.PayPhoneCC, u.PayWuFoo
The results come up like this:
Count Pay1Click PayMailCC PayMailCheck PayPhoneACH PayPhoneCC PayWuFoo
8 0 0 0 0 0 1
25 0 0 0 0 1 0
8 0 0 0 1 0 0
99 0 0 1 0 0 0
11 0 1 0 0 0 0
So the question is, how can I get this to 2 columns, Count and then the headers of the next 6 headers so the results look like this:
Count PaymentType
8 PayWuFoo
25 PayPhoneCC
8 PayPhoneACH
99 PayMailCheck
11 PayMailCC
Thanks.
Try this one
Select Count,
CASE WHEN Pay1Click=1 THEN 'Pay1Click'
PayMailCC=1 THEN ' PayMailCC'
PayMailCheck=1 THEN 'PayMailCheck'
PayPhoneACH=1 THEN 'PayPhoneACH'
PayPhoneCC=1 THEN 'PayPhoneCC'
PayWuFoo=1 THEN 'PayWuFoo'
END as PaymentType
FROM ......
I think indeed you made a mistake in the structure of the second table. Instead of creating a row for each multiple choice question, i would suggest transforming all those columns to a 'answer' column, so you would have the actual name of the alternative as the record in that column.
But for this, you have to change the structure of your tables, and change the way the table is populated. you should get the name of the alternative checked and put it into your table.
More on this, you could care for repetitive data in your table, so writing over and over again the same string could make your table grow larger.
if there are other things implied to the answer, other informations in the UD_Demo_ORG table, then you can normalize the table, creating a payment_dimension table or something like this, give your alternatives an ID such as
ID PaymentType OtherInfo(description, etc)...
1 PayWuFoo ...
2 PayPhoneCC ...
3 PayPhoneACH ...
4 PayMailCheck ...
5 PayMailCC ...
This is called a dimension table, and then in your records, you would have the ID of the payment type, and not the information you don't need.
So instead of a big result set, maybe you could simplify by much your query and have just
Count PaymentId
8 1
25 2
8 3
99 4
11 5
as a result set. it would make the query faster too, and if you need other information, you can then join the table and get it.
BUT if the only field you would have is the name, perhaps you could use the paymentType as the "id" in this case... just consider it. It is scalable if you separate to a dimension table.
Some references for further reading:
http://beginnersbook.com/2015/05/normalization-in-dbms/ "Normalization in DBMS"
http://searchdatamanagement.techtarget.com/answer/What-are-the-differences-between-fact-tables-and-dimension-tables-in-star-schemas "Differences between fact tables and dimensions tables"

MS Access: Count Number of Zero-Records

I'm working with a data set that looks similar to the following:
Name Value
Unit 1 0
Unit 1 27
Unit 1 30
Unit 1 10
Unit 1 4
Unit 1 0
Unit 2 0
Unit 2 0
Unit 2 29
Unit 2 0
Unit 3 10
and so on. I would like to create a query that lists the records as follows:
Name ZeroRecords
Unit 1 2
Unit 2 3
Unit 3 0
Where I can list the number of records that are 0. I've tried using a totals row counting Value's, with a criteria of "=0" but it just turns up blank.
I'm sure this is much easier to do with SQL but I am not very familiar.
Any suggestions?
You could consider grouping your records by the Name property along with a COUNT() aggregate to get the count for each group and if you filter it down to only check the Value columns that are zero, you could use :
SELECT Name,
COUNT(*) AS ZeroRecords
FROM YourTable
WHERE Value = 0
GROUP BY Name
You can use conditional aggregation. In MS Access, this looks like:
select name, sum(iif(value = 0, 1, 0)) as numzeros
from t
group by name;

Conditional SELECT depending on a set of rules

I need to get data from different columns depending on a set of rules and I don't see how to do it. Let me illustrate this with an example. I have a table:
ID ELEM_01 ELEM_02 ELEM_03
---------------------------------
1 0.12 0 100
2 0.14 5 200
3 0.16 10 300
4 0.18 15 400
5 0.20 20 500
And I have a set of rules which look something like this:
P1Z: ID=2 and ELEM_01
P2Z: ID=4 and ELEM_03
P3Z: ID=4 and ELEM_02
P4Z: ID=3 and ELEM_03
I'm trying to output the following:
P1Z P2Z P3Z P4Z
------------------------
0.14 400 15 300
I'm used to much simpler queries and this is a bit above my level. I'm getting mixed up by this problem and I don't see a straightforward solution. Any pointers would be appreciated.
EDIT Logic behind the rules: the table contains data about different aspects of a piece of equipment. Each combination of ID/ELEM_** represents the value of one aspect of the piece of equipment. The table contains all values of all aspects, but we want a row containing data on only a specific subset of aspects, so that we can output in a single table the values of a specific subset of aspects for all pieces of equipment.
Assuming that each column is numeric and ID is unique you could do:
SELECT
SUM(CASE WHEN ID = 2 THEN ELEM_01 END) AS P1Z,
SUM(CASE WHEN ID = 4 THEN ELEM_03 END) AS P2Z,
SUM(CASE WHEN ID = 4 THEN ELEM_02 END) AS P3Z,
SUM(CASE WHEN ID = 3 THEN ELEM_03 END) AS P4Z
...

Separation of data rows based on a flag and timestamp

I want to delete/ignore/separate logs that are useful from logs that are not useful. Logs that are useful occur before or at a time that is known by a flag. Logs that are not useful occur after the first flagged log.
Data looks like this. Each UID seen at time t:
UID t flag PCP
'0000' 1 0 0
'0000' 2 1 0
'0000' 3 1 0
'0000' 4 0 0
'1111' 11 1 0
'1111' 12 0 0
'1111' 13 0 0
'2222' 1 0 0
'2222' 2 0 0
'2222' 3 0 0
Is there a query to input a 0/1 value in PCP so I can get
UID t flag PCP
'0000' 1 0 1
'0000' 2 1 1
'0000' 3 1 0
'0000' 4 0 0
'1111' 11 1 1
'1111' 12 0 0
'1111' 13 0 0
'2222' 1 0 0
'2222' 2 0 0
'2222' 3 0 0
Note: in actuality flag is \in {0,1,2} and I want PCP to reflect flag = 2. So an incremental sum() won't work.
Edit: this question is similar (different end, and I'm not good at SQl enough to know how to get the output I want from this question). Flag dates occurring after an event within individuals
Another edit: in sqlite you can compare strings and ints in >/= operations, and I think in SQL you cannot. My table is all in text, but comparing with integers has been going well enough, and the question above is breaking because of typing in SQL. see http://sqlfiddle.com/#!3/00448/3
I'm basing this answer off of your SQL Fiddle you posted. If UserID and PCP are actual TEXT datatypes, then this should work. If they are actually varchar, then you can replace the LIKE with an = sign.
You simply need to use an exists clause to look for any record with the same userID that has a conversiontagid = 2 and check the time....
Update logs
Set PCP = '1'
Where exists (
select 1
from logs sub
where logs.userid LIKE sub.userid
and sub.conversiontagid = 2
and sub.t >= logs.t
)
I made some assumptions using your SQL fiddle because it's not exactly clear based on your question above. But userID 4 has three records that all occurred at the same time, so I assumed that they should all three have PCP set to 1.
Here is the SQL Fiddle showing the same query used in a select statement instead of an update statement.
SQL Fiddle Example