How to Apply Conditional Logic to Where Statement - sql

I can't seem to figure out how to set the logic up for my particular problem. I'm trying to count the number of times the word "Service" appears but only when the RECORD_CODE is INCIDENT. When the RECORD is INCIDENT-UPDATE, it is normally already somewhere else as an INCIDENT so I exclude them to keep from duplicating my data.
However, there are a small number of cases where the SUBMIT_METHOD is "WEB" and the only record is an INCIDENT_UPDATE and I cannot figure out how to look only where the RECORD = 'INCIDENT' unless the particular record has a SUBMIT_METHOD of "WEB" and there is no record for that report # with a RECORD of INCIDENT. It could be a simple problem and I'm just overthinking it but I cannot think of how to do it. Any help would be GREATLY appreciated!
My query:
SELECT column2, count(*) as 'COUNT'
from Service.Table
where date between '1/1/17' and '1/31/17'
and column1 = 'Issue'
and RECORD = 'INCIDENT'
group by column2
Sample of the data:
REPORT # RECORD SUBMIT_METHOD SUBMIT_DATE COLUMN2
1234 Incident Web 1/1/2017 Service
1234 Incident-Update Web 1/1/2017 Service
1235 Incident Phone 1/15/2017 Other
1235 Incident-Update Phone 1/15/2017 Other
1236 Incident-Update Web 1/18/2017 Service
The expected output in this case would be:
COLUMN2 COUNT
Service 3
If I can provide any other info just let me know!

You are looking for a group by like
select column2, count(*)
from tbl1
where SUBMIT_METHOD = 'Web'
group by column2;

;With cte(REPORT#,RECORD ,SUBMIT_METHOD,SUBMIT_DATE,COLUMN2)
AS
(
SELECT 1234,'Incident' ,'Web' , '1/1/2017' ,'Service' Union all
SELECT 1234,'Incident-Update' ,'Web' , '1/1/2017' ,'Service' Union all
SELECT 1235,'Incident' ,'Phone', '1/15/2017', 'Other' Union all
SELECT 1235,'Incident-Update' ,'Phone', '1/15/2017', 'Other' Union all
SELECT 1236,'Incident-Update' ,'Web' , '1/18/2017', 'Service'
)
SELECT COLUMN2
,CountCOLUMN2
FROM (
SELECT *
,COUNT(COLUMN2) OVER (
PARTITION BY COLUMN2 ORDER BY COLUMN2
) CountCOLUMN2
,ROW_NUMBER() OVER (
PARTITION BY COLUMN2 ORDER BY COLUMN2
) Seq
FROM cte
) Dt
WHERE SUBMIT_DATE BETWEEN '1/1/17'
AND '1/31/17'
AND RECORD = 'INCIDENT'
ORDER BY 1 DESC
OutPut
COLUMN2 CountCOLUMN2
--------------------
Service 3
Other 2

You could use not exists subquery to ensure there is no other row with the same Report# and a record type of INCIDENT:
select *
from Service.Table t1
where date between '1/1/17' and '1/31/17' and
column1 = 'Issue' and
(
record = 'Incident' or
(
record = 'Incident-Update' and
submit_method = 'Web' and
not exist
(
select *
from Service.Table t2
where t2.record = 'INCIDENT'
and t2.[Report #] = t1.[Report #]
)
)
)

Related

How to write a BigQuery query that produces the count of the unique transactions and the combination of column names populated

I’m trying to write a query in BigQuery that produces the count of the unique transactions and the combination of column names populated.
I have a table:
TRAN CODE
Full Name
Given Name
Surname
DOB
Phone
The result set I’m after is:
TRAN CODE
UNIQUE TRANSACTIONS
NAME OF POPULATED COLUMNS
A
3
Full Name
A
4
Full Name,Phone
B
5
Given Name,Surname
B
10
Given Name,Surname,DOB,Phone
The result set shows that for TRAN CODE A
3 distinct customers provided Full Name
4 distinct customers provided Full Name and Phone #
For TRAN CODE B
5 distinct customers provided Given Name and Surname
10 distinct customers provided Given Name, Surname, DOB, Phone #
Currently to produce my results I’m doing it manually.
I tried using ARRAY_AGG but couldn’t get it working.
Any advice work be appreciated.
Thank you.
I think you want something like this:
select tran_code,
array_to_string(array[case when full_name is not null then 'full_name' end,
case when given_name is not null then 'given_name' end,
case when surname is not null then 'surname' end,
case when dob is not null then 'dob' end,
case when phone is not null then 'phone' end
], ','),
count(*)
from t
group by 1, 2
Consider below approach - no any dependency on column names rather than TRAN_CODE - quite generic!
select TRAN_CODE,
count(distinct POPULATED_VALUES) as UNIQUE_TRANSACTIONS,
POPULATED_COLUMNS
from (
select TRAN_CODE,
( select as struct
string_agg(col, ', ' order by offset) POPULATED_COLUMNS,
string_agg(val order by offset) POPULATED_VALUES,
string_agg(cast(offset as string) order by offset) pos
from unnest(regexp_extract_all(to_json_string(t), r'"([^"]+?)":')) col with offset
join unnest(regexp_extract_all(to_json_string(t), r'"[^"]+?":("[^"]+?"|null)')) val with offset
using(offset)
where val != 'null'
and col != 'TRAN_CODE'
).*
from `project.dataset.table` t
)
group by TRAN_CODE, POPULATED_COLUMNS
order by TRAN_CODE, any_value(pos)
below is output example
#Gordon_Linoff's solution is the best, but an alternative would be to do the following:
SELECT
TRAN_CODE,
COUNT(TRAN_ROW) AS unique_transactions,
populated_columns
FROM (
SELECT
TRAN_CODE,
TRAN_ROW,
# COUNT(value) AS unique_transactions,
STRING_AGG(field, ",") AS populated_columns
FROM (
SELECT
* EXCEPT(DOB),
CAST(DOB AS STRING ) AS DOB,
ROW_NUMBER() OVER () AS TRAN_ROW
FROM
sample) UNPIVOT(value FOR field IN (Full_name,
Given_name,
Surname,
DOB,
Phone))
GROUP BY
TRAN_CODE,
TRAN_ROW )
GROUP BY
TRAN_CODE,
populated_columns
But this should be more expensive...

How to Select * Where Everything is Distinct Except One Field

I'm trying to pull 6 records using the code below but there are some cases where the information is updated and therefore it is pulling duplicate records.
My code:
SELECT column2, count(*) as 'Count'
FROM ServiceTable p
join HIERARCHY h
on p.LOCATION_CODE = h.LOCATION
where Report_date between '2017-04-01' and '2017-04-30'
and Column1 = 'Issue '
and LOCATION = '8789'
and
( record_code = 'INCIDENT' or
(
SUBMIT_METHOD = 'Web' and
not exists
(
select *
from ServiceTable p2
where p2.record_code = 'INCIDENT'
and p2.incident_id = p.incident_id
)
)
)
The problem is that instead of the six records it is pulling eight. I would just use distinct * but the file_date is different on the duplicate entries:
FILE_DATE Incident_ID Column1 Column2
4/4/17 123 Issue Service - Red
4/4/17 123 Issue Service - Blue
4/5/17 123 Issue Service - Red
4/5/17 123 Issue Service - Blue
The desired output is:
COLUMN2 COUNT
Service - Red 1
Service - Blue 1
Any help would be greatly appreciated! If you need any other info just let me know.
If you turn your original select statement without the aggregation function into a subquery, you can distinct that on your values that are not the changing date, then select a COUNT from there. Don't forget your GROUP BY clause at the end.
SELECT Column2, COUNT(Incident_ID) AS Service_Count
FROM (SELECT DISTINCT Incident_ID, Column1, Column2
FROM ServiceTable p
JOIN HIERARCHY h ON p.LOCATION_CODE = h.LOCATION
WHERE Report_date BETWEEN '2017-04-01' AND '2017-04-30'
AND Column1 = 'Issue '
AND LOCATION = '8789'
AND
( record_code = 'INCIDENT' or
(
SUBMIT_METHOD = 'Web' and
NOT EXISTS
(
SELECT *
FROM ServiceTable p2
WHERE p2.record_code = 'INCIDENT'
AND p2.incident_id = p.incident_id)
)
)
)
GROUP BY Column2
Also, if you are joining tables it is a good practice to fully qualify the field you are selecting. Example: p.Column2, p.Incident_ID, h.LOCATION. That way, even your distinct fields are easier to follow where they came from and how they relate.
Finally, don't forget that COUNT is a reserved word. I modified your alias accordingly.
If you are using an aggregation function (count), you should use group by for the column not in the aggregation function:
SELECT column2, count(*) as 'Count'
FROM ServiceTable p
join HIERARCHY h
on p.LOCATION_CODE = h.LOCATION
where Report_date between '2017-04-01' and '2017-04-30'
and Column1 = 'Issue '
and LOCATION = '8789'
and
( record_code = 'INCIDENT' or
(
SUBMIT_METHOD = 'Web' and
not exists
(
select *
from ServiceTable p2
where p2.record_code = 'INCIDENT'
and p2.incident_id = p.incident_id
)
)
)
group by column2

How to transpose dynamically in Oracle

Here is my table
Equipmentid Application Value
=========== =========== =====
k001 THK True
k001 BHK False
k001 KHK True
Here is what I expected:
Equipmentid THK BHK KHK
=========== === === ===
k001 True False True
I'm trying to use normal transpose Oracle using max decode but in the end need to mention AS [tablename], I want to dynamically create row to column base on row name, this database will involve very much application. Thank guys
Hi try using PIVOT,
WITH x(equipment_id, application, VALUE )
AS (SELECT 'k001', 'THK', 'TRUE' FROM DUAL UNION ALL
SELECT 'k001', 'BHK', 'FALSE' FROM DUAL UNION ALL
SELECT 'k001', 'KHK', 'TRUE' FROM DUAL UNION ALL
SELECT 'k002', 'KHK', 'FALSE' FROM DUAL UNION ALL
SELECT 'k002', 'THK', 'FALSE' FROM DUAL UNION ALL
SELECT 'k002', 'BHK', 'FALSE' FROM DUAL )
SELECT * FROM
(
SELECT equipment_id, value, application
FROM x
)
PIVOT
(
MAX(value)
FOR application IN ('THK', 'BHK', 'KHK')
) order by equipment_id;
Alternatively, if you want to have dynamic column, you can use subquery in the IN clause then use PIVOT XML,but result will be of XML TYPE which i dont know how to extract the values.(just saying) if you want to know more about how to do it dynamically with pl/sql. Read here .Here's the source
SELECT * FROM
(
SELECT equipment_id, value, application
FROM x
)
PIVOT XML
(
MAX(value)
FOR application IN (SELECT DISTINCT application from x)
) order by equipment_id;
Try this one.
SELECT EQUIPMENTID,
max(case when APPLICATION = 'THK' then VALUE end) as "THK",
max(case when APPLICATION = 'BHK' then VALUE end) as "BHK",
max(case when APPLICATION = 'KHK' then VALUE end) as "KHK"
FROM [tablename]
group by EQUIPMENTID;
You can left join in this case.
SELECT t1.Equipmentid, t2.Value AS 'THK', t3.Value AS 'BHK', t4.Value AS 'KHK' FROM TABLE t1
LEFT JOIN (SELECT Equipmentid, Value FROM TABLE WHERE Application = 'THK') AS t2 ON (t1.Equipmentid = t2.Equipmentid)
LEFT JOIN (SELECT Equipmentid, Value FROM TABLE WHERE Application = 'BHK') AS t3 ON (t1.Equipmentid = t3.Equipmentid)
LEFT JOIN (SELECT Equipmentid, Value FROM TABLE WHERE Application = 'KHK') AS t4 ON (t1.Equipmentid = t4.Equipmentid)
Even though it can be solve. But this method is not good in my opinion. Hope it help you anyway

Grouping by date range combined with another field?

In SQL Server 2008, I have something like the following:
Create table #RateHistory (RatePlan char(1), EventDate datetime)
Insert into #RateHistory (RatePlan, EventDate)
VALUES
('a','10/01/2013')
,('a','10/04/2013')
,('a','10/06/2013')
,('a','10/08/2013')
,('b','10/21/2013')
,('b','11/05/2013')
,('b','11/12/2013')
,('b','12/05/2013')
,('a','12/08/2013')
,('a','12/09/2013')
,('a','12/10/2013')
,('a','12/15/2013')
I'd like to see an output like this:
Rateplan MinDate MaxDate
-------- ----------- -----------
a 2013-10-01 2013-10-08
b 2013-10-21 2013-12-05
a 2013-12-08 2013-12-15
(originally this was a bit different, but I believe this result set makes it clearer what I actually need, which is the correct grouping)
Note that RatePlan "a" shows up twice, and that I want it to be grouped separately - once for the 10/1/2013 to 10/8/2013 data, and once for the 12/8/2013 to 12/15/2013 data. I've got the solution I need with this :
-- Get initial row numbers
;with Test as (
Select
*
,RowNumber = ROW_NUMBER() over (order by EventDate)
from #RateHistory
)
-- Get initial row numbers
, Test2 as (
SelecT
Main.RowNumber
,Main.EventDate
,Main.RatePlan
,FollowingRatePlan = Following.RatePlan
,NewGroup =
case
when Main.RatePlan <> Following.RatePlan
-- if Following RatePlan is null, that means this is the last record
or (Following.RatePlan is null )
then Main.EventDate
else null
end
from Test Main
left join Test following
on Following.RowNumber = Main.RowNumber + 1
)
, Test3 as (
select
#RateHistory.RatePlan
,#RateHistory.EventDate
,MaxDate = min(Test2.NewGroup)
from #RateHistory
join Test2
on #RateHistory .RatePlan = Test2.RatePlan
and #RateHistory .EventDate <= Test2.NewGroup
where Test2.NewGroup is not null
group by
#RateHistory.RatePlan
,#RateHistory.EventDate
)
select Rateplan, MinDate = MIN(EventDate) , MaxDate
from Test3
group by RatePlan,MaxDate
...but I'm thinking - there's GOT to be a better, more elegant way of doing this. Thoughts? If nobody has anything better, I'll just go ahead and put this in as an answer...
Thanks!
I can think of a solution using correlated scalar sub-queries. You tell me if it's more elegant. Or better performing.
select distinct
rh0.RatePlan,
(
select min(EventDate)
from RateHistory rh1
where rh1.RatePlan = rh0.RatePlan
and rh1.EventDate <= rh0.EventDate
and not exists
(
select * from RateHistory rh2
where rh2.RatePlan != rh0.RatePlan
and rh2.EventDate > rh1.EventDate
and rh2.EventDate < rh0.EventDate
)
) as mindate,
(
select max(EventDate)
from RateHistory rh1
where rh1.RatePlan = rh0.RatePlan
and rh1.EventDate >= rh0.EventDate
and not exists
(
select * from RateHistory rh2
where rh2.RatePlan != rh0.RatePlan
and rh2.EventDate < rh1.EventDate
and rh2.EventDate > rh0.EventDate
)
) as maxdate
from RateHistory rh0
order by mindate
Check out the SQLFiddle. BTW 2012 has some cool features that could make your version of the query more elegant.

How to check existence of data in a table from a where clause in sql server 2008?

Suppose I have a table with columns user_id, name and the table contains data like this:
user_id name
------- -----
sou souhardya
cha chanchal
swa swapan
ari arindam
ran ranadeep
If I want to know these users (sou, cha, ana, agn, swa) exists in this table or not then I want output like this:
user_id it exists or not
------- -----------------
sou y
cha y
ana n
agn n
swa y
As ana and aga do not exist in the table it must show "n" (like the above output).
Assuming your existing checklist is not on the database, you will have to assemble a query containing those. There are many ways of doing it. Using CTEs, it would look like this:
with cte as
(
select 'sou' user_id
union all
select 'cha'
union all
select 'ana'
union all
select 'agn'
union all
select 'swa'
)
select
cte.user_id,
case when yt.user_id is null then 'n' else 'y' end
from cte
left join YourTable yt on cte.user_id = yt.user_id
This also assumes user_id is unique.
Here is the SQLFiddle with the proof of concept: http://sqlfiddle.com/#!3/e023a0/4
Assuming you're just testing this manually:
DECLARE #Users TABLE
(
[user_id] VARCHAR(50)
)
INSERT INTO #Users
SELECT 'sou'
UNION SELECT 'cha'
UNION SELECT 'ana'
UNION SELECT 'agn'
UNION SELECT 'swa'
SELECT a.[user_id]
, [name]
, CASE
WHEN b.[user_id] IS NULL THEN 'N'
ELSE 'Y'
END AS [exists_or_not]
FROM [your_table] a
LEFT JOIN #Users b
ON a.[user_id] = b.[user_id]
You didn't provide quite enough information to provide a working example, but this should get you close:
select tbl1.user_id, case tbl2.user_id is null then 'n' else 'y' end
from tbl1 left outer join tbl2 on tbl1.user_id = tbl2.user_id
;with usersToCheck as
(
select 'sou' as userid
union select 'cha'
union select 'ana'
union select 'agn'
union select 'swa'
)
select utc.userid,
(case when exists ( select * from usersTable as ut where ut.user_id = utc.userid) then 'y' else 'n' end)
from usersToCheck as utc