Without going into too much detail - I need to create groups (grouped on a specific field) of data and then display all GROUPS of records that contain a parameter. I need all records in a GROUP even if some do not match the parameter. Any GROUPS where no records contain the parameter would be suppressed.
I'm working with db2 and I just need help with the basic syntax. I'm thinking a PARTITION_BY used within a subquery might be the correct approach. Any ideas? Thanks in advance.
Does it answer the question ?
with table1 (group_column, expression, other_column) as (
values
('group1', 'false', 'First in G1'),
('group1', 'false', 'Second in G1'),
('group2', 'false', 'First in G2'),
('group2', 'true', 'Second in G2'),
('group3', 'true', 'Full G3')
)
select
table1.group_column, expression, other_column
from table1
inner join
(
select
distinct group_column
from table1
where expression = 'true'
) as groups on table1.group_column = groups.group_column
GROUP_COLUMN
EXPRESSION
OTHER_COLUMN
group2
false
First in G2
group2
true
Second in G2
group3
true
Full G3
Related
I am working with address records in an Oracle db. Each row contains information on two parents. There are four columns for phone number types and four columns for numbers. The types are Other_No_Type_1, Other_No_Type_2, Other_No_Type_3, Other_No_Type_4 and any one of them might contain a value of either 'Name1:Mobile', 'Name2:Mobile', 'Father Work', or 'Mother Work', That value refers to the number in the next column (Other_No_1, Other_No_2, Other_No_3 or Other_No_4). I need to pull the Other_No_x value when Other_No_Type_x is equal to Name1:Mobile and alias it "contact_1_mobile" and pull Name2:Mobile and alias it "contact_2_mobile". In my SELECT below, you can see that I've just written "a.other_no_1 as contact_1_mobile" for example, but actually that might be retrieving a work number or the Name2:mobile number. This is my first request for help to the forum, so I apologize for probably not presenting my question properly. Thank you for any help you can give. Here is my statement as it stands now:
SELECT final.*
FROM (
SELECT
--Name 1 in P1 household
a.id
,a.name1_web_user_id as contact_1_id
,a.name1_full_name as contact_1_name
,a.other_no_1 as contact_1_mobile (THIS IS MY PROBLEM. "Other_No_1" MAY NOT ACTUALLY BE THE NAME1:MOBILE NUMBER TYPE I NEED. THIS PROBLEM IS THE SAME IN EACH SECTION OF MY STATEMENT.)
,a.email as contact_1_email
--Name 2 in P1 household
,a.name2_web_user_id as contact_2_id
,a.name2_full_name as contact_2_name
,a.other_no_2 as contact_2_mobile (PROBLEM: HERE I ACTUALLY NEED TO FIND THE COLUMN THAT CONTAINS THE "Name2:Mobile" NUMBER)
,a.EMAIL_2 as contact_2_email
FROM rg_student s left outer join rg_addr a on s.id = a.id
WHERE (
(a.addr_code='P1' AND a.rg_active = 'Y') AND ((a.name1_web_user_id is not null) OR (a.name2_web_user_id is not null))
AND a.id in(SELECT id from rg_student where student_group='Student')
)
UNION
SELECT
--Name 1 in P2 household
a.id
,a.name1_web_user_id as contact_3_id
,a.name1_full_name as contact_3_name
,a.other_no_1 as contact_3_mobile (PROBLEM LINE)
,a.email as contact_3_email
--Name 2 in P2 household
,a.name2_web_user_id as contact_4_id
,a.name2_full_name as contact_4_name
,a.other_no_2 as contact_4_mobile (PROBLEM LINE)
,a.EMAIL_2 as contact_4_email
FROM rg_student s left outer join rg_addr a on s.id = a.id
WHERE (
(a.addr_code='P2' AND a.rg_active = 'Y') AND ((a.name1_web_user_id is not null) OR (a.name2_web_user_id is not null))
AND a.id in(SELECT id from rg_student where student_group='Student')
)
)final
ORDER BY final.id
Just use case or decode:
case 'Name1:Mobile'
when Other_No_Type_1 then Other_No_1
when Other_No_Type_2 then Other_No_2
when Other_No_Type_3 then Other_No_3
when Other_No_Type_4 then Other_No_4
end as contact_1_mobile
I'm improving a report that currently uses a static table using the lookup function to fill its data from a few different datasets. We're pretty sure this is causing the report to take a lot longer to run, so I'm trying to use a table that uses column groups to achieve the same effect from a single dataset.
Here's what my query currently looks like. This functions exactly as I want it to as long as there's data.
Select CatName, CatCount, Category = 'Category 1', Sorting = 1
FROM
(Select CatName, Count(CatName) as CatCount FROM DataSet WHERE Parameters)
UNION
Select CatName, CatCount, Category = 'Category 2', Sorting = 2
FROM
(Select CatName, Count(CatName) as CatCount FROM DataSet WHERE Parameters)
When there are CatNames and CatCounts to pull from the select statement, the Category works and is pulled by the table as a column group. I need all of the groups to exist at all times.
However, sometimes we don't have data that fits the parameters for a category. The result when that happens is that there isn't a row for the Category field to use and that group doesn't exist in the table. Is there any way I can force the Category field to exist regardless of the data?
If I understand the question correctly, then you may be able to use ISNULL. ISNULL returns either the value you were for which you were looking (check_expression) or the alternative (replacement_value) if check_expression is NULL.
ISNULL ( check_expression , replacement_value )
Select CatName, CatCount, Category = 'Category 2', Sorting = 2
FROM
(Select isnull(CatName,""), Count(CatName) as CatCount FROM DataSet WHERE Parameters)
EDIT
How about a left outer join?
Select b.CatName, b.CatCount, Category = 'Category 2', Sorting = 2
FROM
(select '' as CatName, 0 as Catcount) a left outer join (Select CatName, Count(CatName) as CatCount FROM DataSet WHERE Parameters) b on a.CatName = b.CatName
Found a solution. Took a few tries, not the prettiest, and we'll have to see if it actually improves performance, but it works the way we wanted. Generalized code:
Select C.CatName, C.CatCount, Category = 'Category 1', Sorting = 1
FROM
(Select Top 5 B.CatName, Count(B.CatName) as CatCount
FROM
(Select CatName = case when CatOnlyParam in (Category1Filter) then A.CatName else NULL end
FROM
(Select CatName FROM DataSet WHERE GeneralParameters) as A
) as B
order by CatCount
) as C
UNION
etc
Separating the parameters into different steps guarantees that there will be values for each category, even if those values are NULL. I'm sure there's a cleaner way to get the same effect, but this functions.
Working from the inside out:
Stage 1 (Select statement A): Selects the value from the dataset with very general parameters (between a start and end date, resolved or not, etc).
Stage 2 (Select statement B): Uses the case statement to only pull the data that is relevant for this department while leaving behind NULLs for the data that isn't.
Stage 3 (Select statement C): Takes the data from the list of names and NULLs and gets a count from it. Sorts by that count and takes the top 5. If a category has no data, then the nulls will get "counted" to 0 and passed on to the final step.
Stage 4 (Final select statement): Adds the static fields to the information from the previous step. A category without data will get passed to this as:
CatName: NULL
CatCount: 0
Category: "Category 1"
Sorting: 1
Then this is repeated for the other categories and UNION'd together. Any suggestions to improve this are more than welcome.
I have one student grade of null that I manually need to add in the below as an f (to match a grade received and reported previously). I am trying to find a way to do this in SQL Server without having to do it in Excel.
Here is what I have in the select statement for the grades portion (also showing that I am doing the group by roll up at the end):
SELECT
CASE grouping (STC_GRADE)
WHEN 1 THEN 'total' ELSE STC_GRADE
END AS 'MARK ANALYSIS'....
GROUP BY ROLLUP (STC_GRADE)...
How would I add into that select statement that if the STC_GRADE IS NULL to count it as an F so that the results show as:
'38' `F`'s
instead of '1' null and '37' F's?
To replace a NULL with a non-NULL value, you use this:
SELECT ISNULL(stc_grade, 'F') AS stc_grade
FROM your_table
I have an application that is grabbing data from an Access database. I am seeking the minimum value of a column and the results I am getting back are inconsistent.
Have I run into a feature where Access inconsistently treating an empty string as a null depending on whether I add a filter or not, or is there something wrong with the way I am querying the data?
The column contains one blank value (not null) and several non-blank values that are all identical (about 30 instances of 'QLD'). The query I am using has a filter that involves multiple other tables, so that only the blank value and about half of the 'QLD' values are eligible.
It's probably easier to show the code and the effects rather than describe it. I have created a series of unioned queries which 'should' bring back identical results but do not.
Query:
SELECT 'min(LOC_STATE)' as Category
, min(LOC_STATE) as Result
FROM pay_run, pay_run_employee, employee, department, location
WHERE pr_id = pre_prid
AND em_location = loc_id
AND pre_empnum = em_empnum
AND em_department = dm_id
AND pr_date >= #2/24/2015#
AND pr_date <= #2/24/2016#
UNION ALL
(SELECT TOP 1 'top 1 LOC_STATE'
, LOC_STATE
FROM pay_run, pay_run_employee, employee, department, location
WHERE pr_id = pre_prid
AND em_location = loc_id
AND pre_empnum = em_empnum
AND em_department = dm_id
AND pr_date >= #2/24/2015#
AND pr_date <= #2/24/2016#
ORDER BY LOC_STATE)
UNION ALL
SELECT 'min unfiltered', min(loc_state)
FROM location
UNION ALL
(SELECT TOP 1 'iif is null', iif(loc_state is null, 'a', loc_state)
FROM location
ORDER BY loc_state)
Results:
Category Result
min(LOC_STATE) 'QLD'
top 1 LOC_STATE ''
min unfiltered ''
iif is null ''
If I do a minimum with the filter it brings back 'QLD' and not the empty string. At this stage it is possible that the empty string is not being included because it is treated as a null or the filter removes it.
The second query, which brings back the top 1 state using the filter shows that the empty string is not filtered out, which means that the Min function is ignoring the empty string.
The third query, which gets the minimum of the unfiltered table, brings back the empty string - so the minimum function does not exclude empty strings / treat them as null.
The fourth query, ensures that there is not a null in the empty string position.
My conclusion is that perhaps the inclusion of other tables and filter criteria is causing the empty string value to be treated as a null, but I feel that I must be missing something.
NB: I have a very similar query (date literals altered) that executes against the same data imported into a SQL Server database. It is correctly returning '' for all 4 queries.
Does anyone know why the empty string is ignored by the Min function in the first query?
PS: for those who prefer a query with joins
SELECT 'min(LOC_STATE)' as Category
, min(LOC_STATE) as Result
FROM (((pay_run
INNER JOIN pay_run_employee ON pay_run.pr_id = pay_run_employee.pre_prid)
INNER JOIN employee ON pay_run_employee.pre_empnum = employee.em_empnum)
INNER JOIN department ON employee.em_department = department.dm_id)
INNER JOIN location on employee.em_location = location.loc_id
WHERE
PR_DATE >= #2/24/2015# and
PR_DATE <= #2/24/2016#
union all
(SELECT TOP 1 'TOP 1 LOC_STATE'
, LOC_STATE
FROM (((pay_run
INNER JOIN pay_run_employee ON pay_run.pr_id = pay_run_employee.pre_prid)
INNER JOIN employee ON pay_run_employee.pre_empnum = employee.em_empnum)
INNER JOIN department ON employee.em_department = department.dm_id)
INNER JOIN location on employee.em_location = location.loc_id
WHERE
PR_DATE >= #2/24/2015# and
PR_DATE <= #2/24/2016#
order by LOC_STATE)
union all
select 'min unfiltered', min(loc_state)
from location
This has got nothing to do with corrupt data or unions or joins. The problem can be easily made visible by exectuting following queries in access:
create table testbug (Field1 varchar (255) NULL)
insert into testbug (Field1) values ('a')
insert into testbug (Field1) values ('')
insert into testbug (Field1) values ('c')
select min(field1) from testbug
To my opinion this is a bug in ms-access. When the MIN function in ms-access comes across an empty string ('') it forgets all the values he has come across and returns the minimum value from all the values below the empty string. (in my simple example only value 'c')
MySQL provides a string function named FIELD() which accepts a variable number of arguments. The return value is the location of the first argument in the list of the remaining ones. In other words:
FIELD('d', 'a', 'b', 'c', 'd', 'e', 'f')
would return 4 since 'd' is the fourth argument following the first.
This function provides the capability to sort a query's results based on a very specific ordering. For my current application there are four statuses that I need to manager: active, approved, rejected, and submitted. However, if I simply order by the status column, I feel the usability of the resulting list is lessened since rejected and active status items are more important than submitted and approved ones.
In MySQL I could do this:
SELECT <stuff> FROM <table> WHERE <conditions> ORDER BY FIELD(status, 'rejected', 'active','submitted', 'approved')
and the results would be ordered such that rejected items were first, followed by active ones, and so on. Thus, the results were ordered in decreasing levels of importance to the visitor.
I could create a separate table which enumerates this importance level for the statuses and then order the query by that in descending order, but this has come up for me a few times since switching to MS SQL Server so I thought I'd inquire as to whether or not I could avoid the extra table and the somewhat more complex queries using a built-in function similar to MySQL's FIELD().
Thank you,
David Kees
Use a CASE expression (SQL Server 2005+):
ORDER BY CASE status
WHEN 'active' THEN 1
WHEN 'approved' THEN 2
WHEN 'rejected' THEN 3
WHEN 'submitted' THEN 4
ELSE 5
END
You can use this syntax for more complex evaluation (including combinations, or if you need to use LIKE)
ORDER BY CASE
WHEN status LIKE 'active' THEN 1
WHEN status LIKE 'approved' THEN 2
WHEN status LIKE 'rejected' THEN 3
WHEN status LIKE 'submitted' THEN 4
ELSE 5
END
For your particular example your could:
ORDER BY CHARINDEX(
',' + status + ',',
',rejected,active,submitted,approved,'
)
Note that FIELD is supposed to return 0, 1, 2, 3, 4 where as the above will return 0, 1, 10, 17 and 27 so this trick is only useful inside the order by clause.
A set based approach would be to outer join with a table-valued-constructor:
LEFT JOIN (VALUES
('rejected', 1),
('active', 2),
('submitted', 3),
('approved', 4)
) AS lu(status, sort_order)
...
ORDER BY lu.sort_order
I recommend a CTE (SQL server 2005+).
No need to repeat the status codes or create the separate table.
WITH cte(status, RN) AS ( -- CTE to create ordered list and define where clause
SELECT 'active', 1
UNION SELECT 'approved', 2
UNION SELECT 'rejected', 3
UNION SELECT 'submitted', 4
)
SELECT <field1>, <field2>
FROM <table> tbl
INNER JOIN cte ON cte.status = tbl.status -- do the join
ORDER BY cte.RN -- use the ordering defined in the cte
Good luck,
Jason
ORDER BY CHARINDEX(','+convert(varchar,status)+',' ,
',rejected,active,submitted,approved,')
just put a comma before and after a string in which you are finding the substring index or you can say that second parameter.
and first parameter of charindex is also surrounded by ,