How to create sql selection based on condition? - sql

I have the following database which shows characteristics of attributes as follows:
attributeId | attributeCode | groupCode
------------+---------------+-----------
1 | 10 | 50
1 | 10 | 50
1 | 12 | 50
My desired result from a select would be:
attributeId | groupcount | code10 | code12
------------+------------+--------+--------
1 | 1 | 2 | 1
Which means: attributeId = 1 has only one groupCode (50), where attributeCode=10 occurs 2 times and attributeCode=12 occurs 1 time.
Of course the following is not valid, but you get the idea of what I'm trying to achieve:
select attributeId,
count(distinct(groupCode)) as groupcount,
attributeCode = 10 as code10,
attributeCode = 12 as code12
from table
group by attributeId;

Try this:
SELECT attributeId, COUNT(DISTINCT groupCode) AS groupcount,
COUNT(CASE WHEN attributeCode = 10 THEN 1 END) AS code10,
COUNT(CASE WHEN attributeCode = 12 THEN 1 END) AS code12
FROM mytable
GROUP BY attributeId
Demo here

Related

Oracle SQL: Dividing Counts into unique and non unique columns

I have a table that looks like this:
|FileID| File Info |
| ---- | ------------ |
| 1 | X |
| 1 | Y |
| 2 | Y |
| 2 | Z |
| 2 | A |
I want to aggregate by FileID and split the File Info column into 2 separate count columns. I want 1 column to have the count of the Unique File Info and the other to be a count of non-Unique file info.
The result would ideally look like this:
|FileID| Count(Unique)| Count(Non-unique) |
| ---- | ------------ | ----------------- |
| 1 | 1 | 1 |
| 2 | 2 | 1 |
where the non-unique count is the 'Y' and the unique count is from the 'X' and 'Z, A' for FileID 1 and 2 respectively.
I'm looking for ways to gauge uniqueness between files rather than within.
Use COUNT() window function in every row to check if FileInfo is unique and then use conditional aggregation to get the results that you want:
SELECT FileID,
COUNT(CASE WHEN counter = 1 THEN 1 END) count_unique,
COUNT(CASE WHEN counter > 1 THEN 1 END) count_non_unique
FROM (
SELECT t.*, COUNT(*) OVER (PARTITION BY t.FileInfo) counter
FROM tablename t
) t
GROUP BY FileID;
See the demo.
First you select the "Non Unique" rows from the table
SELECT FileInfo
FROM sometableyoudidnotname
GROUP BY FileInfo
HAVING COUNT(*) > 1
Now that you know which ones are unique and non unique you can left join to that table to get the "status" and count it up.
SELECT base.FileID,
SUM(CASE WHEN u.FileID is NOT NULL THEN 1 ELSE 0 END) as nonunique,
SUM(CASE WHEN u.FileID is NULL THEN 1 ELSE 0 END) as unique
FROM sometableyoudidnotname base
LEFT JOIN (
SELECT FileInfo
FROM sometableyoudidnotname
GROUP BY FileInfo
HAVING COUNT(*) > 1
) u ON base.FileInfo = u.FileInfo
GROUP BY base.FileID
Have a derived table that counts occurrences of each fileid. JOIN and GROUP BY:
select t1.FileID,
sum(case when t2.ficount = 1 then 1 else 0 end),
sum(case when t2.ficount > 1 then 1 else 0 end)
from tablename t1
join
(
select fileinfo, count(*) ficount
from tablename
group by fileinfo
) t2
on t1.fileinfo = t2.fileinfo
group by t1.FileID

How can I seperate one column into multiple columns depending on their value when selecting it?

I have a table called assignment_answers, which has the following attributes:
assignment_answers_id, question_id and order. The order is an attribute, which can take a value from 0 to 9.
I would like for every value that it can take to make it be displayed in a different column. For instance when the order has value 0, then I want it to be displayed in a column called number0. When it has value 1 I want it to be displayed in a column called number1.
Could someone help me with that? So far I have tried this but it does not work:
SELECT (CASE WHEN assessment_answers.order = 0
THEN(
select aq.order as number0
from assessment_answers)
END)
(CASE WHEN assessment_answers.order = 1
THEN(
select aq.order as number1
from assessment_answers)
END)
FROM assessment_answers
I get an error saying:
ERROR: syntax error at or near "("
LINE 6: (CASE WHEN assessment_questions."order" = 1
SAMPLE DATA
assignment_answers_id question_id order
1 1 0
2 1 0
3 2 1
desired output:
assignment_answers_id question_id order0 order1
1 1 0 null
2 1 0 null
3 2 null 1
You can try to use normal CASE WHEN
Query 1:
SELECT assignment_answers_id,
question_id,
(CASE WHEN order = 0 THEN order END) order0,
(CASE WHEN order = 1 THEN order END) order1
FROM assessment_answers
Results:
| assignment_answers_id | question_id | order0 | order1 |
|-----------------------|-------------|--------|--------|
| 1 | 1 | 0 | (null) |
| 2 | 1 | 0 | (null) |
| 3 | 2 | (null) | 1 |
Does this do what you want?
select (aa.order = 0)::int as order_0,
(aa.order = 1)::int as order_1,
(aa.order = 2)::int as order_2,
. . .
from assessment_answers aa;

How to fetch records from complex database?

I need to fetch multiple records and single records at a time with multiple tables from MSSQL. Tables from where I need to collect data is like below :
1. tblExpenseType :
--> ExpenseTypeId | ExpenseTypeName
--> 1 | OVERTIME EXP.
--> 2 | REPAIRING EXP.
--> 3 | LU EXP.
2. tblMemoDetails :
--> MemoID | MemoNumber | FkTruckId
--> 1011 | 1 | 5
--> 1012 | 2 | 6
--> 1013 | 3 | 5
--> 1014 | 4 | 7
3. tblMemoExpense :
--> FkMemoNumber | FkExpenseTypeId | Amount
--> 1 | 1 | 150
--> 1 | 3 | 225
--> 2 | 1 | 50
--> 2 | 2 | 100
--> 2 | 3 | 150
4. tblMemoTrips :
--> FkTripId | FkMemoNumber | TripAmount
--> 11 | 1 | 1000
--> 9 | 2 | 500
--> 3 | 2 | 100
--> 4 | 2 | 2000
I'm trying to fetch data using below logic but it's making me confusing:
with MemoList
As
(select
_jpMemo.MemoId as memoId
from TMS_JPMemo _jpMemo
where _jpMemo.FkTruckId = 5)
select
ML.memoId
--,ME.FkExpenseTypeId
,ME.Amount
,ET.ExpenseTypeName
from TMS_MemoExpense ME
join MemoList ML on ML.memoId = ME.FkMemoId
join TMS_ExpenseTypes ET on ET.ExpenseTypeId = ME.FkExpenseTypeId
I need result like if I select FkTruckId 5 then it will show me below result.
I need results like below for FkTruckId 5 :
MemoNumber | TripDetails | TripAmount | OVERTIME | REPAIRING | LU
1 | 11 | 1000 | 150 | -- | 225
| Total | 1000 | 150 | -- | 225
And If I select FkTruckId 6 then it would show me a result like :
MemoNumber | TripDetails | TripAmount | OVERTIME | REPAIRING | LU
2 | 9 | 500 | -- | -- | --
| 3 | 100 | -- | -- | --
| 4 | 2000 | 50 | 100 | 150
| Total | 2600 | 50 | 100 | 150
So it's making me confusing how to solve this and how to achieve this type of complex data from tables.
You are displaying two different things per memo:
the memo's trips with their trip amount
the memo's expenses
Apart from belonging to the same memo, the two are not related, i.e. there are no expenses per trip. So it's actually two different things you want to show. Make this two separate queries. You can glue them together with UNION ALL, as you obviously want them both in one query result. Something like:
with memo as
(
select memoid
from tblmemodetails
where fktruckid = 5
)
select memonumber, tripid, tripamount, overtime, repairing, lu
from
(
-- -------------------------------------------------------------------------------
-- The memos' trips. They have a trip amount but no further expenses of their own.
select
fkmemonumber as memonumber,
fktripid as tripid,
tripamount,
null as overtime,
null as repairing,
null as lu,
1 sortkey
from tblmemotrips
where fkmemonumber in (select memonumber from memo)
group by fkmemonumber, fktripid -- one row per memo and trip
-- -------------------------------------------------------------------------------
union all
-- -------------------------------------------------------------------------------
-- The memos' expenses. They are not reated to particular trips.
select
fkmemonumber as memonumber,
null as tripid,
null as tripamount,
sum(case when fkexpensetypeid = 1 then amount end) as overtime,
sum(case when fkexpensetypeid = 2 then amount end) as repairing,
sum(case when fkexpensetypeid = 3 then amount end) as lu,
2 as sortkey
from tblmemoexpense
where fkmemonumber in (select memonumber from memo)
group by fkmemonumber -- one row per memo
-- -------------------------------------------------------------------------------
) data
order by memonumber, sortkey;
You could use a series of JOINs to put the tables in relation, and then conditional aggregation to pivot the data. This implies that the number of columns to pivot is fixed (if more values are added to table tblExpenseType, the query would need to be adapted) :
SELECT
md.MemoNumber,
mt.FkTripId AS TripDetails,
mt.TripAmount,
MAX(CASE WHEN et.ExpenseTypeName = 'OVERTIME EXP.' THEN me.amount END) AS OVERTIME,
MAX(CASE WHEN et.ExpenseTypeName = 'REPARINING EXP.' THEN me.amount END) AS REPARING,
MAX(CASE WHEN et.ExpenseTypeName = 'LU EXP.' THEN me.amount END) AS LU
FROM
tblMemoDetails AS md
LEFT JOIN tblMemoExpense AS me ON me.FkMemoNumber = md.MemoNumber
LEFT JOIN tblMemoTrips AS mt ON mt.FkMemoNumber = md.MemoNumber
LEFT JOIN tblExpenseType AS et ON et.ExpenseTypeId = me.FkExpenseTypeId
GROUP BY
md.MemoNumber,
mt.FkTripId AS TripDetails,
mt.TripAmount
Conditional aggregation is the way to go. I think the query looks a little more like this:
SELECT md.TruckId, md.MemoNumber,
COALESCE(mt.FkTripId, 'Total') AS TripDetails, mt.TripAmount,
SUM(CASE WHEN et.ExpenseTypeName = 'OVERTIME EXP.' THEN me.amount ELSE 0 END) AS OVERTIME,
SUM(CASE WHEN et.ExpenseTypeName = 'REPARINING EXP.' THEN me.amount ELSE 0 END) AS REPARING,
SUM(CASE WHEN et.ExpenseTypeName = 'LU EXP.' THEN me.amount ELSE 0 END) AS LU
FROM tblMemoDetails md LEFT JOIN
tblMemoExpense me
ON me.FkMemoNumber = md.MemoNumber LEFT JOIN
tblMemoTrips mt
ON mt.FkMemoNumber = md.MemoNumber LEFT JOIN
tblExpenseType et
ON et.ExpenseTypeId = me.FkExpenseTypeId
WHERE md.TruckId = #TruckId
GROUP BY GROUPING SETS ( (md.TruckId, md.MemoNumber, mt.FkTripId, mt.TripAmount), () );
The GROUPING SETS generates the total.

how to group column as per its unique value and get count in to different column as per its value?

I am having a Category table as follows,
i want retrieve following results according to scStatusvalue and its count group by catID
catID | 0 | 2 | 3
----- |---|---|---
2 | 1 | 0 | 1
3 | 1 | 1 | 0
4 | 2 | 0 | 1
5 | 0 | 1 | 0
I tried this,select catID,count(scStatus) as [Count] from tableName group by catID,scStatus order by catID but i cant get into column that values.
`
Use a pivot query:
SELECT catID,
SUM(CASE WHEN scStatus = 0 THEN 1 ELSE 0 END) AS [0],
SUM(CASE WHEN scStatus = 2 THEN 1 ELSE 0 END) AS [2],
SUM(CASE WHEN scStatus = 3 THEN 1 ELSE 0 END) AS [3]
FROM Category
GROUP BY catID
pivot operator
select *
from (select catID,scStatusvalue from t) t
pivot (count(scStatusvalue) for scStatusvalue in ([0],[2],[3])) t

Count who paid group by 1, 2 or 3+

I have a payment table like the example below and I need a query that gives me how many IDs paid (AMOUNT > 0) 1 time, 2 times, 3 or more times. Example:
+----+--------+
| ID | AMOUNT |
+----+--------+
| 1 | 50 |
| 1 | 0 |
| 2 | 10 |
| 2 | 20 |
| 2 | 15 |
| 2 | 10 |
| 3 | 80 |
+----+--------+
I expect the result:
+-----------+------------+-------------+
| 1 payment | 2 payments | 3+ payments |
+-----------+------------+-------------+
| 2 | 0 | 1 |
+-----------+------------+-------------+
ID 1: Paid 1 time (50). The other payment is 0, so I did not count. So, 1 person paid 1 time.
ID 2: Paid 3 times (10,20,15). So, 1 person paid 3 or more time.
ID 3: Paid 1 time (80). So, 2 persons paid 1 time.
I'm doing manually on excel right now but I'm pretty sure there is a more practical solution. Any ideas?
A little sub-query will do the trick
Declare #YOurTable table (ID int, AMOUNT int)
Insert into #YourTable values
( 1 , 50 ),
( 1 , 0) ,
( 2 , 10) ,
( 2 , 20) ,
( 2 , 15) ,
( 2 , 10) ,
( 3 , 80)
Select [1_Payment] = sum(case when Cnt=1 then 1 else 0 end)
,[2_Payment] = sum(case when Cnt=2 then 1 else 0 end)
,[3_Payment] = sum(case when Cnt>2 then 1 else 0 end)
From (
Select id
,Cnt=count(*)
From #YourTable
Where Amount<>0
Group By ID
) A
Returns
1_Payment 2_Payment 3_Payment
2 0 1
To get the output you want try using a table to form the data and then SELECT from that:
with c as (
select count(*) count from mytable where amount > 0 group by id)
select
sum(case count when 1 then 1 else 0 end) "1 Payment"
, sum(case count when 2 then 1 else 0 end) "2 Payments"
, sum(case when count > 2 then 1 else 0 end) "3 Payments"
from c
Here is an example you can play with to see how the query is working.