view data from database table - sql

SELECT dun, COUNT( id_ahli ) AS JUMLAH_KESELURUHAN, COUNT(kaum='melayu') AS melayu, COUNT(kaum='cina') AS cina
FROM maklumat_ahli
WHERE jantina = 'lelaki'
AND
(kematian_tarikh IS NULL)
AND (bayaran_pertama IS NULL)
AND (bayaran_kedua IS NULL)
GROUP BY dun
ORDER BY dun
this is my sql statement. Is it posible to count and view data by kaum?. i use that sql statement, but my count is not correct
/-----------------------------------------/
|dun | Jumlah_keseluruhan | melayu | cina |
-------------------------------------------
|A |123 |100 |23 |
-------------------------------------------
is it any possible way to view data from db like the table above.

To count data by special value you may use CASE clause
COUNT(case when kaum='melayu' then 1 else 0 end) AS melayu,
COUNT(case when kaum='cina'the 1 else 0 end) AS cina

Related

How to create a table to count with a conditional

I have a database with a lot of columns with pass, fail, blank indicators
I want to create a function to count each type of value and create a table from the counts. The structure I am thinking is something like
| Value | x | y | z |
|-------|------------------|-------------------|---|---|---|---|---|---|---|
| pass | count if x=pass | count if y=pass | count if z=pass | | | | | | |
| fail | count if x=fail | count if y=fail |count if z=fail | | | | | | |
| blank | count if x=blank | count if y=blank | count if z=blank | | | | | | |
| total | count(x) | count(y) | count (z) | | | | | | |
where x,y,z are columns from another table.
I don't know which could be the best approach for this
thank you all in advance
I tried this structure but it shows syntax error
CREATE FUNCTION Countif (columnx nvarchar(20),value_compare nvarchar(10))
RETURNS Count_column_x AS
BEGIN
IF columnx=value_compare
count(columnx)
END
RETURN
END
Also, I don't know how to add each count to the actual table I am trying to create
Conditional counting (or any conditional aggregation) can often be done inline by placing a CASE expression inside the aggregate function that conditionally returns the value to be aggregated or a NULL to skip.
An example would be COUNT(CASE WHEN SelectMe = 1 THEN 1 END). Here the aggregated value is 1 (which could be any non-null value for COUNT(). (For other aggregate functions, a more meaningful value would be provided.) The implicit ELSE returns a NULL which is not counted.
For you problem, I believe the first thing to do is to UNPIVOT your data, placing the column name and values side-by-side. You can then group by value and use conditional aggregation as described above to calculate your results. After a few more details to add (1) a totals row using WITH ROLLUP, (2) a CASE statement to adjust the labels for the blank and total rows, and (3) some ORDER BY tricks to get the results right and we are done.
The results may be something like:
SELECT
CASE
WHEN GROUPING(U.Value) = 1 THEN 'Total'
WHEN U.Value = '' THEN 'Blank'
ELSE U.Value
END AS Value,
COUNT(CASE WHEN U.Col = 'x' THEN 1 END) AS x,
COUNT(CASE WHEN U.Col = 'y' THEN 1 END) AS y
FROM #Data D
UNPIVOT (
Value
FOR Col IN (x, y)
) AS U
GROUP BY U.Value WITH ROLLUP
ORDER BY
GROUPING(U.Value),
CASE U.Value WHEN 'Pass' THEN 1 WHEN 'Fail' THEN 2 WHEN '' THEN 3 ELSE 4 END,
U.VALUE
Sample data:
x
y
Pass
Pass
Pass
Fail
Pass
Fail
Sample results:
Value
x
y
Pass
3
1
Fail
1
1
Blank
0
2
Total
4
4
See this db<>fiddle for a working example.
I think you don't need a generic solution like a function with value as parameter.
Perhaps, you could create a view grouping your data and after call this view filtering by your value.
Your view body would be something like that
select value, count(*) as Total
from table_name
group by value
Feel free to explain your situation better so I could help you.
You can do this by grouping by the status column.
select status, count(*) as total
from some_table
group by status
Rather than making a whole new table, consider using a view. This is a query that looks like a table.
create view status_counts as
select status, count(*) as total
from some_table
group by status
You can then select total from status_counts where status = 'pass' or the like and it will run the query.
You can also create a "materialized view". This is like a view, but the results are written to a real table. SQL Server is special in that it will keep this table up to date for you.
create materialized view status_counts with distribution(hash(status))
select status, count(*) as total
from some_table
group by status
You'd do this for performance reasons on a large table which does not update very often.

MS-Access Query to PostgreSQL View

I am converting a microsoft access query into a postgresql view. The query has obvious components that I have found reasonable answers to. However, I am still stuck on getting the final result:
SELECT All_Claim_Data.Sec_ID,
Sum(IIf([Type]="LODE",IIf([Status]="Active",1,0),0)) AS LD_Actv,
Sum(IIf([Type]="LODE",IIf([Loc_Date]>#8/31/2017#,IIf([Loc_Date]<#9/1/2018#,1,0),0),0)) AS LD_stkd_17_18,
Sum(IIf([Type]="LODE",IIf([Loc_Date]>#8/31/2016#,IIf([Loc_Date]<#9/1/2017#,1,0),0),0)) AS LD_stkd_16_17,
Sum(IIf([Type]="LODE",IIf([Loc_Date]<#1/1/1910#,IIf(IsNull([Clsd_Date]),1,(IIf([Clsd_Date]>#1/1/1900#,1,0))),0),0)) AS Actv_1900s,
Sum(IIf([Type]="LODE",IIf([Loc_Date]<#1/1/1920#,IIf(IsNull([Clsd_Date]),1,(IIf([Clsd_Date]>#1/1/1910#,1,0))),0),0)) AS Actv_1910s,
FROM All_Claim_Data.Sec_ID,
GROUP BY All_Claim_Data.Sec_ID,
HAVING (((Sum(IIf([casetype_txt]="LODE",1,0)))>0));
Realizing I need to use CASE SUM WHEN, here is what I have worked out so far:
CREATE OR REPLACE VIEW hgeditor.vw_test AS
SELECT All_Claim_Data.Sec_ID,
SUM (CASE WHEN(Type='LODE' AND WHEN(Status='Active',1,0),0)) AS LD_Actv,
SUM (CASE WHEN(Type='LODE' AND WHEN(Loc_Date>'8/31/2017' AND Loc_Date<'9/1/2018',1,0),0),0)) AS LD_stkd_17_18,
SUM (CASE WHEN(Type='LODE' AND WHEN(Loc_Date<'1/1/1910' AND (IsNull(Clsd_Date),1,(WHEN([Clsd_Date]>'1/1/1900',1,0))),0),0)) AS Actv_1900s
FROM All_Claim_Data.Sec_ID,
GROUP BY All_Claim_Data.Sec_ID,
HAVING (((SUM(IIf(Type='LODE',1,0)))>0));
The goal is to count the number of instances in which the Sec_ID has the following:
has (Type = LODE and Status = Active) = SUM integer
has (Type = LODE and Loc_Date between 8/31/2017 and 9/1/2018) = SUM Integer
My primary issue is getting a SUM integer to populate in the new columns
Case expressions are the equivalent to the Access IIF() functions, but WHEN isn't a function so it isn't used by passing a set of parameters. Think of it as being a tiny where clause instead, it evaluates one or more predicates to determine what to do, and the action taken is established by what you specify after THEN
CREATE OR REPLACE VIEW hgeditor.vw_test AS
SELECT
All_Claim_Data.Sec_ID
, SUM( CASE
WHEN TYPE = 'LODE' AND
STATUS = 'Active' THEN 1
ELSE 0
END ) AS LD_Actv
, SUM( CASE
WHEN TYPE = 'LODE' AND
Loc_Date > to_date('08/31/2017','mm/dd/yyyy') AND
Loc_Date < to_date('09/1/2018','mm/dd/yyyy') THEN 1
ELSE 0
END ) AS LD_stkd_17_18
, SUM( CASE
WHEN TYPE = 'LODE' AND
Loc_Date < to_date('1/1/1910','mm/dd/yyyy') AND
[Clsd_Date] > to_date('1/1/1900','mm/dd/yyyy') THEN 1
ELSE 0
END ) AS Actv_1900s
FROM All_Claim_Data.Sec_ID
GROUP BY
All_Claim_Data.Sec_ID
HAVING COUNT( CASE
WHEN Type = 'LODE' THEN 1
END ) > 0
;
By the way, you should NOT be relying on MM/DD/YYYY as dates in Postgres
nb: Aggregate functions ignore NULL, take this example:
+----------+
| id value |
+----------+
| 1 x |
| 2 NULL |
| 3 x |
| 4 NULL |
| 5 x |
+----------+
select
count(*) c_all
, count(value) c_value
from t
+-------+----------+
| c_all | c_value |
+-------+----------+
| 5 | 3 |
+-------+----------+
select
sum(case when value IS NOT NULL then 1 else 0 end) sum_case
, count(case when value IS NOT NULL then 1 end) count_case
from t
+----------+-------------+
| sum_case | count_case |
+----------+-------------+
| 3 | 3 |
+----------+-------------+

Transpose row-columns and Counting number of instances per column in SQLITE

I have a table structured as
|creationDate|rule. |position|
|01.01.2018 |squid:S1132|12 |
|01.01.2018 |squid:S1132|14 |
|01.01.2018 |squid:S1132|19 |
|01.01.2018 |squid:S1121|12 |
|01.01.2018 |squid:S1121|14 |
|01.02.2018 |squid:S1130|12 |
My goal is to count the number of rules per date, reporting them in different columns.
|creationDate| S1132 | S1121 | S1130 |
|01.01.2018 | 3 |2 | 0 |
|01.02.2018 | 0 |0 | 1 |
I have a total of 180 rules...
Is it possible to make it in a single query?
Running this query
select creationDate , count("creationDate") as "squid:S1132"
from SONAR_ISSUES
where rule='squid:S1132' group by creationDate
I obtain this result
|creationDate|S1132 |
|01.01.2018 |3 |
I can do a similar query for each rule, but then, I am not able to merge them...
try by using case when
select creationDate ,count(case when rule='squid:S1132' then 1 end) as S1132,
count(case when rule='squid:S1121' then 1 end) as S1121,
count(case when rule='squid:S1130' then 1 end) as S1130
from SONAR_ISSUES
group by
creationDate
You can try using conditional aggregation
DEMO
select
creationDate,
count(case when rule='squid:S1132' then "creationDate" end) as "squid:S1132",
count(case when rule='squid:S1121' then "creationDate" end) as "squid:S1121" ,
count(case when rule='squid:S1130' then "creationDate" end) as "squid:S1130"
from SONAR_ISSUES
group by creationDate

SQL average multiple columns for each row with nulls

I have a table like this:
|Quality|Schedule|Cost Control|
-------------------------------
|7 | 8.5 |10 |
|NULL | 9 |NULL |
and I need to calculate the average of each row in the same table so it looks like this:
|Quality|Schedule|Cost Control|AVG|
----------------------------------
|7 | 8.5 |10 |8.5|
|NULL | 9 |NULL |9 |
which I have done using the following code:
SELECT r.Quality, r.Schedule, r.CostControl,
((coalesce(r.quality,0)+
coalesce(r.schedule,0)+
coalesce(r.CostControl,0)/3) as Average
FROM dbo.Rating r
Which gives the following table:
|Quality|Schedule|Cost Control|AVG|
----------------------------------
|7 | 8.5 |10 |8.5|
|NULL | 9 |NULL |3 |
I know the problem is that the divisor is hard coded in my select statement, but I can't figure out how to make it variable. I tried using a case statement to select an addition column:
select Count(case when(r.quality) > 0 then 1 else 0 end +
case when (r.Schedule) > 0 then 1 else 0 end +
case when (r.CostControl) > 0 then 1 else 0 end)
But that only gives me one value. I'm out of ideas and facing a pretty tight deadline, so any help would be much appreciated.
Instead of dividing by 3, use
(CASE WHEN Quality IS NULL THEN 0 ELSE 1 END +
CASE WHEN Schedule IS NULL THEN 0 ELSE 1 END +
CASE WHEN [Cost Control] IS NULL THEN 0 ELSE 1 END)
I would use apply instead :
select *, (select sum(v) / count(v)
from ( values (quality), (Schedule), (CostControl)
) tt(v)
) as AVG
from table t;
I would use apply with avg():
SELECT r.Quality, r.Schedule, r.CostControl, v.average
FROM dbo.Rating r CROSS APPLY
(SELECT avg(val)
FROM (VALUES (quality), (schedule), (CostControl)) v(val)
) v(average);
This requires no subqueries, no long case expressions, generalizes easily to more columns, runs no risk of divide-by-zero . . . and the performance might even be equivalent to the case expression.

Get the result set based on column's first character in SQL Server?

I have following table structure.
Table : Vehicle
+--------+--------+-------+----------+
| Diesel | Petrol | LPG | Hybrid |
+--------+--------+-------+----------+
| yes | no | no | no |
| no | yes | no | no |
| no | no | yes | no |
| no | no | no | yes |
+--------+--------+-------+----------+
I want to retrieve records set based column's first character from stored procedure parameter. So far I have tried below query.
My #FuelType Parameter value looks like 'D,P,L'.
Select * from Vehicle
Where (Diesel = Case When CharIndex('D', #FuelType) > 0 Then 'yes'
Else 'no' End)
Or (Petrol = Case When CharIndex('P', #FuelType) > 0 Then 'yes'
Else 'no' End)
Or (LPG = Case When CharIndex('L', #FuelType) > 0 Then 'yes'
Else 'no' End)
Or (Hybrid = Case When CharIndex('H', #FuelType) > 0 Then 'yes'
Else 'no' End)
Is there any possibility available to optimize the above query?
I don't know about the query, but there's certainly an opportunity to better normalize the schema design. You have a many-to-many relationship between vehicles and fuel types. You should resolve this with a junction table.
Your query can then become something like:
SELECT v.*
FROM Vehicle v
INNER JOIN Vehicle_FuelType_Xref vftx
ON v.VehicleID = vftx.VehicleID
INNER JOIN Fuel_Type ft
ON vftx.FuelTypeID = ft.FuelTypeID
WHERE ft.FuelType IN ('Diesel', 'Petrol', 'LPG');