I have a table with the next structure
Table A:
| Id | 1 | 2 | 3 |
|-----|---------|----------|-----------|
| 1 | 00:05:00| 00:10:00 | (null) |
| 2 | 00:10:00| (null) | (null) |
Table B
| Id | col |Expected |
|-----|---------|----------|
| 1 | 1 | 00:06:00 |
| 2 | 2 | 00:12:00 |
| 3 | 3 | 00:22:00 |
I am trying to make a sum depending on the actual value on the rows of table A in comparison to the expected on table B
Select
Id, (Select ??????? From (Select TiempoStd from B)as Stime) as Time
From
A
Basically i want to make a comparison between the 2 tables to see which one is greater and add that to the next one.
I cant manage to understand how to call a specific value under my temp table Stime.
i am not that familiar with SQL so thats why i cant get this, the logic is something like this. in where the question marks are on the Query
ADDTIME(IF(A.1>(Stime.Expected where col = 1),A.1,(Stime.Expected where col = 1)),
ADDTIME(IF(A.2>(Stime.Expected where col = 2),A.2,(Stime.Expected where col = 2)),
IF(A.3>(Stime.Expected where col = 3),A.3,(Stime.Expected where col = 3))
Stime.Expected where col = 3 is a bad syntax right? but i hope you get the point of the logic im trying to make here.
so the output would be like this
| Id | Time |
|-----|---------|
| 1 | 00:40:00|
| 2 | 00:44:00|
Use a UNION to convert table A to a table with separate rows for each column, then join this with table B.
select *
FROM TableB AS b
JOIN (SELECT Id, 1 AS col, a.1 AS Time
FROM TableA as a
UNION
SELECT Id, 2 AS col, a.2 AS Time
FROM TableA AS a
UNION
SELECT Id, 3 AS col, a.3 AS Time
FROM TableA AS a) AS a
ON a.Id = b.Id AND a.col = b.col
This made the trick, i got help from some friends and got to it, gives the desired result.
SELECT
A.Id,
addtime(
addtime(
ifnull(Case when A.1 > E.Expected1 Then A.1 else E.expected1 end,'00:00:00') ,
ifnull(Case when A.2 > E.Expected2 Then A.2 else E.expected2 end,'00:00:00')
), ifnull(Case when A.3 > E.Expected3 Then A.3 else E.expected3 end,'00:00:00')
) as Time
From TableA A, (
SELECT
sum(case when col=1 Then Expected else 0 end) as Expected1,
sum(case when col=2 Then Expected else 0 end) as Expected2,
sum(case when col=3 Then Expected else 0 end) as Expected3
From TableB ) as E
Related
I have a fairly big table (10,000+ records) that looks more or less like this:
| id | name | contract_no | status |
|----|-------|-------------|--------|
| 1 | name1 | 1022 | A |
| 2 | name2 | 1856 | B |
| 3 | name3 | 1322 | C |
| 4 | name4 | 1322 | C |
| 5 | name5 | 1322 | D |
contract_no is a foreign key which of course can appear in several records and each record will have a status of either A, B, C, D or E.
What I want is to get a list of all the contract numbers, where ALL the records referencing that contract are in status C, D, E, or a mix of those, but if any of the records are in status A or B, omit that contract number.
Is it possible to do this using a SQL query? Or should I better export the data and try to run this analysis using another language like Python or R?
Post aggregate filtering should do the trick
SELECT contract_no FROM t
GROUP BY contract_no
HAVING SUM(status='A')=0
AND SUM(status='B')=0
You can use group by with having to get such contract numbers.
select contract_number
from yourtable
group by contract_number
having count(distinct case when status in ('C','D','E') then status end) >= 1
and count(case when status = 'A' then 1 end) = 0
and count(case when status = 'B' then 1 end) = 0
Not that elegant as the other two answers, but more expressive:
SELECT DISTINCT contract_no
FROM the_table t1
WHERE NOT EXISTS (
SELECT *
FROM the_table t2
WHERE t2.contract_no = t1.contract_no
AND t2.status IN ('A', 'B')
)
Or
SELECT DISTINCT contract_no
FROM the_table
WHERE contract_no NOT IN (
SELECT contract_no
FROM the_table
AND status IN ('A', 'B')
)
Here's an example Table layout:
TABLE_A: TABLE_B: TABLE_A_B:
id | a | b | c id | name a_id | b_id
--------------------- --------- -----------
1 | true | X | A 1 | A 1 | 1
2 | true | Z | null 2 | B 1 | 2
3 | false | X | null 3 | C 2 | 2
4 | true | Y | Q 4 | 1
5 | false | null | null 4 | 2
5 | 1
Possible Values:
TABLE_A.a: true, false
TABLE_A.b: X, Y, Z
TABLE_A.c: A, B, C, ... basically arbitrary
TABLE_B.name: A, B, C, ... basically arbitrary
What I want to achieve:
SELECT all rows from TABLE_A
SUM(where a = true),
SUM(where a = false),
SUM(where b = 'X'),
SUM(where b = 'Y'),
SUM(where b = 'Z'),
SUM(where b IS NULL),
and also get the SUMs for all distinct TABLE_A.c values.
and also get the SUMs for all those TABLE_A_B relations.
The result for the example Table above should look like:
aTrue | aFalse | bX | bY | bZ | bNull | cA | cQ | cNull | nameA | nameB | nameC
-------------------------------------------------------------------------------
3 | 2 | 2 | 1 | 1 | 1 | 1 | 1 | 3 | 3 | 3 | 0
What I've done so far:
SELECT
SUM(CASE WHEN a = true THEN 1 ELSE 0 END) AS aTrue,
SUM(CASE WHEN b = false THEN 1 ELSE 0 END) AS aFalse,
SUM(CASE WHEN b = 'X' THEN 1 ELSE 0 END) AS bX,
...
FROM TABLE_A
What's my problem?
Selecting column TABLE_A.a and TABLE_A.b is easy, because there's a fixed number of possible values.
But I can't figure out how to count the distinct values of TABLE_A.c. And basically the same problem for the JOINed TABLE_B, because the number of values within TABLE_B is unknown and can change over time.
Thanks for your help! :)
EDIT1: New (preferred) SQL result structure:
column | value | sum
----------------------------
TABLE_A.a | true | 3
TABLE_A.a | false | 2
TABLE_A.b | X | 2
TABLE_A.b | Y | 1
TABLE_A.b | Z | 1
TABLE_A.b | null | 1
TABLE_A.c | A | 1
TABLE_A.c | Q | 1
TABLE_A.c | null | 3
TABLE_B.name | A | 3
TABLE_B.name | B | 3
TABLE_B.name | C | 0
From your original request of rows as a simulated pivot. By doing a SUM( logical condition ) basically returns 1 if true, 0 if false. So, since the column "a" is true or false, simple sum of "a" or NOT "a" (for the false counts -- NOT FALSE = TRUE). Similarly, your "b" column, so b='X' = true counted as 1, else 0.
In other sql engines, you might see it as SUM( case/when ).
Now, since your table counts don't rely on each other, they can be separate SUM() into their own sub-alias query references (pqA and pqB for pre-queryA and pre-queryB respectively). Since no group by, they will each result in a single row. With no join will create a Cartesian, but since 1:1 ratio, will only return a single record of all columns you want.
SELECT
pqA.*, pqB.*
from
( SELECT
SUM( ta.a ) aTrue,
SUM( NOT ta.a ) aFalse,
SUM( ta.b = 'X' ) bX,
SUM( ta.b = 'Y' ) bY,
SUM( ta.b = 'Z' ) bZ,
SUM( ta.b is null ) bNULL,
SUM( ta.c = 'A' ) cA,
SUM( ta.c = 'Q' ) cQ,
SUM( ta.c is null ) cNULL,
COUNT( distinct ta.c ) DistC
from
table_a ta ) pqA,
( SELECT
SUM( b.Name = 'A' ) nameA,
SUM( b.Name = 'B' ) nameB,
SUM( b.Name = 'C' ) nameC
from
table_a_b t_ab
join table_b b
ON t_ab.b_id = b.id ) pqB
This option gives your second (preferred) output
SELECT
MAX( 'TABLE_A.a ' ) as Basis,
CASE when a then 'true' else 'false' end Value,
COUNT(*) finalCnt
from
TABLE_A
group by
a
UNION ALL
SELECT
MAX( 'TABLE_A.b ' ) as Basis,
b Value,
COUNT(*) finalCnt
from
TABLE_A
group by
b
UNION ALL
SELECT
MAX( 'TABLE_A.c ' ) as Basis,
c Value,
COUNT(*) finalCnt
from
TABLE_A
group by
c
UNION ALL
SELECT
MAX( 'TABLE_B.name ' ) as Basis,
b.Name Value,
COUNT(*) finalCnt
from
table_a_b t_ab
join table_b b
ON t_ab.b_id = b.id
group by
b.Name
I think You will need to build dynamic query as you don't know possible values for column C in table A. So you can write store procedure where you can get list of distinct value for Column C in one variable and by using "Do WHILE" you can construct your dynamic query.
Please let me know if you need more help in detail
Dynamic SQL
Assuming I have something like this :
MySQL Table
Date | Name | Val
22/11 | a | 1
22/11 | b | 2
22/11 | a | 3
22/11 | a | 4
23/11 | b | 1
23/11 | a | 2
23/11 | a | 3
23/11 | a | 5
I need a query to have on one column the sum of the values for each day when Name = 'a' and an other column for the sum of all the values (for each day too).
With my example, the result would be something like this :
Date | a.Total | Total
22/11 | 8 | 10
23/11 | 10 | 11
I tried something like this :
SELECT date, SUM(Val) AS a.Total, SUM(Val) AS Total FROM tbl1 Where Name = 'a'
The point is that I need to specify a WHERE clause to get the "a.total" values (WHERE Name = 'a') but I don't want it to be apply to get the total.
I also tried queries with Left Join but it didn't work.
Any help is much appreciated.
You should use GROUP BY and CASE inside of the first SUM()
SELECT date,
SUM( CASE WHEN Name='a'
THEN Val
ELSE 0
END) AS a_Total,
SUM(Val) AS Total
FROM tbl1
GROUP BY `Date`
SQLFiddle demo
This is a type of problem called cross-tabbing (see https://www.simple-talk.com/sql/t-sql-programming/creating-cross-tab-queries-and-pivot-tables-in-sql/)
What you're after is the use of a CASE statement to allow you to sum values only when a condition is met.
SELECT date, SUM(CASE WHEN Name='a' then Val end) AS a.Total, SUM(Val) AS Total FROM tbl1 GROUP BY date
I have the following table:
id | group | value
1 | 1 | 10
2 | 1 | 20
3 | 1 | 30
4 | 0 | 20
5 | 0 | 20
6 | 0 | 10
I want to return the highest value where the group is 1 (=30) and all of the values where the group is 0, into one resultset.
I have to do this in one statement, and I guess I should use an IF statement within a SELECT statement, but I can't work out how. Can anyone help to point me in the right direction?
(select max(value) from the_table where group = 1)
union
(select value from the_table where group = 0)
If (group +value) is unique, you can also do it without union (as proposed by Ray Toal)
SELECT a.value
FROM table1 a
WHERE a.`group`=0 or (a.`group`=1 AND a.value =
(SELECT MAX(value) FROM table1 b WHERE b.`group`=1))
I want to count the number of records in database from more than two tables that are joined.
For example I have a table like this.
table
jobd + name
1 | jobA
2 | jobB
tableA
imgeid + orderid + jobid
1 | 1 | 1
2 | 2 | 1
3 | 3 | 1
4 | 4 | 1 (this order is not yet started)
tableB
taskid + orderid + task + status
1 | 1 | 1 | UPDATED
2 | 1 | 1 | UPDATED
3 | 1 | 1 | COMPLETED
4 | 2 | 2 | SAVED
5 | 3 | 3 | COMPLETED
My problem here is that when I count base on status (# tableB) my query results both the UPDATED which has the same orderid.
This is my sample query that same with the one I'm working.
SELECT t.name
COUNT(CASE WHEN tb.task = 1 AND tb.status <> 'COMPLETED' THEN tb.status ELSE NULL END) inprogress,
COUNT(CASE WHEN tb.task = 1 AND tb.status = 'COMPLETED' THEN tb.status ELSE NULL END) completed
FROM tableA ta
LEFT JOIN tableB tb
ON tb.orderid = ta.orderid
LEFT JOIN table t
ON t.jobid = ta.jobid
GROUP BY t.jobid;
My results something like
name + inprogress + completed
jobA | 2 | 1
The inprogress results must only be 1 because it has the same orderid. The reason why it has two UPDATED because this table is HISTORICAL. I don't know how can get the distinct orderid in tableB so it will only results to 1.
The main point here is that I can count the total orders which status is in progress, completed and not started per job.
I hope my question is clear. If you have other way, please let me know. Thanks
Can't you use a Count distinct? Here's a link, see nearer the bottom of the page, it will only the unique field you specify: w3schools.com/sql/sql_func_count.asp
SELECT t.name
COUNT(DISTINCT tb.orderid CASE WHEN tb.task = 1 AND tb.status 'COMPLETED' THEN tb.status
ELSE NULL END) inprogress,
COUNT(DISTINCT tb.orderid CASE WHEN tb.task = 1 AND tb.status = 'COMPLETED' THEN tb.status
ELSE NULL END) completed