I have searched for answers but find myself more confused. I am not as experienced - but with low staff - and just me creating reports - I have to create this.
Client has asked for a report that will return MTD answers on survey questions that are stored in 2 databases. Problem is - they want records that are attached to each submitted answer that are not a part of the survey. i.e. each respondent has a information regarding what type of phone they have, area they live in, model of phone and days of service. (these are not answers though)
Many of them are unique. (Models and Cities)
So for example I have created a stored procedure in SQL to pull into SSRS to display results.
But each one is a select and I am only getting the first result. I tried adding UNION ALL but it doesn't seem to let me group them when I do this. I get everything in one column, where as I need them in separate columns - horizontally ideally. But that may be asking too much.
Here is an example - perhaps there is a quicker way - this is a monstrous project - and my deadline is running short now - and I have tried so many things - and searching. Nothing left to do but ask for help.
So here is what I have -
ALTER PROCEDURE [dbo].[TEST_WIRELESS_DISCO_SURVEY_RESULTS]
(
#STARTDATE DATETIME,
#ENDDATE DATETIME
)
AS
BEGIN
SELECT
a.CUSTOM17 as 'Make', COUNT(ISNULL(A.custom17, 0)) as 'Total Make'
FROM GCI_SURVEYS as a
JOIN GCI_Post_Survey_PreRepair_Master as b ON a.CustAcctNo = b.CustAcctNo
WHERE b.Trans_Date between #STARTDATE and #ENDDATE
AND a.i3_rowid = 'GCI_WRLSDISC_BSV'
AND a.Q01 = 'no'
GROUP BY CUSTOM17
UNION ALL
SELECT
a.CUSTOM22 as 'Market', COUNT(ISNULL(a.CUSTOM22, 0)) as 'Total Market'
FROM GCI_SURVEYS as a
JOIN GCI_Post_Survey_PreRepair_Master as b ON a.CustAcctNo = b.CustAcctNo
WHERE b.Trans_Date between #STARTDATE and #ENDDATE
AND a.i3_rowid = 'GCI_WRLSDISC_BSV'
AND a.Q01 = 'no'
GROUP BY a.CUSTOM22
From your explanation, I would think that the top part of the union and the bottom contain the same surveys, just different parts?
I personally would load them into variable tables (or if alot of records, tempoary tables), and then join them together.
DECLARE #MakeQuestion TABLE
(
survery_id INT --datatype
,make VARCHAR(200) --replace with your own
,total_make INT
)
INSERT INTO #MakeQuestion
SELECT a.join_condition, a.CUSTOM17 as 'Make',COUNT(ISNULL(A.custom17,0)) as 'Total Make'
FROM GCI_SURVEYS as a
JOIN GCI_Post_Survey_PreRepair_Master as b
ON a.CustAcctNo = b.CustAcctNo
WHERE b.Trans_Date between #STARTDATE and #ENDDATE
AND a.i3_rowid = 'GCI_WRLSDISC_BSV'
AND a.Q01 = 'no'
GROUP BY a.join_condition,CUSTOM17
DECLARE #MarketQuestion TABLE
(
survery_id INT -- datatype
,market VARCHAR(200) --replace with your own
,total_market INT
)
Insert INTO #MarketQuestion
SELECT a.join_condition, a.CUSTOM22 as 'Market',COUNT(ISNULL(a.CUSTOM22,0)) as 'Total Market'
FROM GCI_SURVEYS as a
JOIN GCI_Post_Survey_PreRepair_Master as b
ON a.CustAcctNo = b.CustAcctNo
WHERE b.Trans_Date between #STARTDATE and #ENDDATE
AND a.i3_rowid = 'GCI_WRLSDISC_BSV'
AND a.Q01 = 'no'
GROUP BY a.CUSTOM22
SELECT *
FROM #MakeQuestion Make
INNER JOIN #MarketQuestion Market ON Make.survey_id = Market.survery_id
Please let me know if i misunderstood.
In the Question you stated that you are fetching data from two Database
return MTD answers on survey questions that are stored in 2 databases
In you SP you are Selecting from the same the DB
Just add the Database Name in one of your Select Query
Related
I am trying to wrap my head around this problem. I was asked to create a report that show repeat customers in our database.
One of the requirements is if a customer has more than 1 order on a specific date, it would only count as 1.
Then if they have more than 1 purchase date, they would then count as a repeat customer.
Searching on here, I found this which works for finding the Customers with more then 1 purchase on a specific purchase date.
SELECT DISTINCT s.[CustomerName], s.PurchaseDate
FROM Reports.vw_Repeat s WHERE s.PurchaseDate <> ''
GROUP BY s.[CustomerName] , cast(s.PurchaseDate as date)
HAVING COUNT(*) > 1;
This MSSQL code works like it should, by showing customers who had more than 1 purchase on the same date.
My problem is what would the best approach be to Join this into another query (this is where i need help) that then shows a complete repeat customer list where customers with more than 1 purchase would be returned.
I am using MSSQL. Any help would be greatly appreciated.
You're close, you need to move distinct into your having clause because you want to include only customers that have more than 1 distinct purchase date.
Also, only group by the customer id because the different dates have to be part of the same group for count distinct to work.
SELECT s.[CustomerName], COUNT(distinct cast(s.PurchaseDate as date))
FROM Reports.vw_Repeat s WHERE s.PurchaseDate <> ''
GROUP BY s.[CustomerName]
HAVING COUNT(distinct cast(s.PurchaseDate as date)) > 1;
If you want to pass a parameter to a query and join the result, that's what table-valued functions are for. When you join it, you use CROSS APPLY or OUTER APPLY instead of an INNER JOIN or a LEFT JOIN.
Also, I think this goes without saying, but when you check if PurchaseDate is empty:
WHERE s.PurchaseDate <> ''
Could be issues there... it implies it's a varchar field instead of a datetime (yes?) and doesn't handle null values. You might, at least, want to replace that with ISNULL(s.PurchaseDate, '') <> ''. If it's actually a datetime, use IS NOT NULL instead of <> ''.
(Edited to add sample data and DDL statements. I recommend adding these to SQL posts to assist answerers. Also, I made purchasedate a varchar instead of a datetime because of the string comparison in the query.)
https://technet.microsoft.com/en-us/library/ms191165(v=sql.105).aspx
CREATE TABLE company (company_name VARCHAR(25))
INSERT INTO company VALUES ('Company1'), ('Company2')
CREATE TABLE vw_repeat (customername VARCHAR(25), purchasedate VARCHAR(25), company VARCHAR(25))
INSERT INTO vw_repeat VALUES ('Cust1', '11/16/2017', 'Company1')
INSERT INTO vw_repeat VALUES ('Cust1', '11/16/2017', 'Company1')
INSERT INTO vw_repeat VALUES ('Cust2', '11/16/2017', 'Company2')
CREATE FUNCTION [dbo].tf_customers
(
#company varchar(25)
)
RETURNS TABLE AS RETURN
(
SELECT s.[CustomerName], cast(s.PurchaseDate as date) PurchaseDate
FROM vw_Repeat s
WHERE s.PurchaseDate <> '' AND s.Company = #company
GROUP BY s.[CustomerName] , cast(s.PurchaseDate as date)
HAVING COUNT(*) > 1
)
GO
SELECT *
FROM company c
CROSS APPLY tf_customers(c.company_name)
First thanks to everyone for the help.
#MaxSzczurek suggested I use table-valued functions. After looking into this more, I ended up using just a temporary table first to get the DISTINCT purchase dates for each Customer. I then loaded that into another temp table RIGHT JOINED to the main table. This gave me the result I was looking for. Its a little(lot) ugly, but it works.
This is a problem that has troubled several times in the past an I have always wondered if a solution is possible.
I have a query using several tables one of the values is mobile phone number.
I have name, addresss etc.... I also have income information in the table which is used for a summary in Excel.
Where the problem occurs is when a contact has more than one mobile number, as you know this will create extra rows with the majority of the data being duplicate including the income.
Question: is it possible for the query to identify whether the contact has more than one number and if so create a new column with the 2nd mobile number.
Effectively returning the contacts information to one row and creating new columns.
My SQL is intermediate and I cannot think of a solution so thought I would ask.
Many thanks
I am pretty sure that it isn't the best possible solution, since we don't have information on how many records do you have in your dataset and I didn't have enough time, so just an idea how you can solve your original problem with two different numbers for one same customer.
declare #t table (id int
,firstName varchar(20)
,lastName varchar(20)
,phoneNumber varchar(20)
,income money)
insert into #t values
(1,'John','Doe','1234567',50)
,(1,'John','Doe','6789856',50)
,(2,'Mike','Smith','5687456',150)
,(3,'Stela','Hodhson','3334445',500)
,(4,'Nick','Slotter','5556667',550)
,(4,'Nick','Slotter','8889991',550)
,(5,'Abraham','Lincoln','4578912',52)
,(6,'Ronald','Regan','6987456',587)
,(7,'Thomas','Jefferson','8745612',300);
with a as(
select id
,max(phoneNumber) maxPhone
from #t group by id
),
b as(
select id
,min(phoneNumber) minPhone
from #t group by id
)
SELECT distinct t.id
,t.firstName
,t.lastName
,t.income
,a.maxPhone as phoneNumber1
,case when b.minPhone = a.maxPhone then ''
else b.minphone end as phoneNumber2
from #t t
inner join a a on a.id = t.id
inner join b b on b.id = t.id
I have two tables: EmployeeMaster and EmployeeDetails. The schema of both are as below:
Sample data in both tables is shown:
I want to generate the hierarchy using EmployeeDetails table primarily. This table contains a column named: Manager. The EmployeeId of the Manager needs to be picked from the table EmployeeMaster table.
This is how the hierarchy needs to be formed. An EmployeeId is passed as a parameter to a stored procedure. The two supervisors of this Employee needs to be picked and 10 employees below this employee in seniority needs to be picked.
For instance, I pass the EmployeeId of Josh.Berkus to the stored procedure. The stored procedure query should return hierarchy as below:
I want the final output in this format:
Employee_Id .... Manager_Id
----------- .... ------------
Please note that Manager_Id is the EmployeeId of Manager.
I tried using a CTE with union all query, but not able to get it correctly.
Actually you will need to work out the recursivity since on manager can have a manager...
take a look at:
http://msdn.microsoft.com/en-us/library/ms190766(v=sql.105).aspx
http://msdn.microsoft.com/en-us/library/ms186243(v=sql.105).aspx
The thing is that your going to need 2 queries... one to go "up" the hierarchy and one to go down... and then union the results...
why don't you merge the two tables, since one person cant have 2 managers right?!? Specially because a manager is also a employee... this will simplify everything...
You can use a CROSS JOIN to create a link between all your records and then you can put the condition to select only those columns that have a manager-employee relationship between them.
The code should be something like this:
SELECT
ed.employeeid 'Employee ID',
em.employeeid 'Manager ID',
FROM EMPLOYEEMASTER em CROSS JOIN EMPLOYEEDETAILS ed
WHERE ed.manager = em.username
You’ll need to implement some recursion here in order to get full hierarchy.
Here is a quick and dirty example of how you can implement this to get manager hierarchy. You would need something similar for lower level hierarchy too
create function dbo.GetManagerHierarchy
(
#EmpID int
)
returns varchar(100)
as
begin
declare #result varchar(100)
declare #managerId int
SET #managerId = (select top 1 Manager from EmployeeDetails where EMployeeId)
if #managerId is not null then
SET #result = dbo.GetManagerHierarchy(#managerID) + '-' + CONVERT(varchar(100), #managerId) +
else
SET #result = ''
return #result
end
My query returns 6 rows when run on production server. But when the same query is used to build SSRS report, it returns only the first 2 rows of the data when run in production. I have been trying to get the issue sorted for 2 days now. Any help is appreciated!
Here's the query:
declare #StartDate varchar(255), declare #EndDate varchar(255)
select I.CustomerIdName AS 'Customer Name', COUNT(S.[Subject]) AS'Activities'
from dbo.Incident I
FULL OUTER JOIN
dbo.ServiceAppointment S
on I.IncidentId = S.RegardingObjectId
FULL OUTER JOIN
dbo.Account A
on A.AccountId = I.AccountId
JOIN
FilteredAccount AS CRMAF_FilteredAccount ON CRMAF_FilteredAccount.accountid = I.CustomerId
WHERE I.CustomerIdName IS NOT NULL
AND (S.ScheduledStart BETWEEN CAST(#StartDate AS datetime) AND CAST(#EndDate as datetime))
GROUP BY I.CustomerIdName,A.OwnerIdYomiName
Couple of things to check.
Filters : Check your SSRS table for filters you may have placed on
Cached data : Go to the root of your solution and delete any .data files and re-rubn your report
Connections : You mention you have production? Logic dictates you have a Dev. Check your data-sources are point the right way.
Writing my first SQL query to run specifically as a SQL Job and I'm a little out of my depth. I have a table within a SQL Server 2005 Database which is populated each day with data from various buildings. To monitor the system better, I am attempting to write a SQL Job that will run a query (or stored procedure) to verify the following:
- At least one row of data appears each day per building
My question has two main parts;
How can I verify that data exists for each building? While there is a "building" column, I'm not sure how to verify each one. I need the query/sp to fail unless all locations have reported it. Do I need to create a control table for the query/sp to compare against? (as the number of building reporting in can change)
How do I make this query fail so that the SQL Job fails? Do I need to wrap it in some sort of error handling code?
Table:
Employee RawDate Building
Bob 2010-07-22 06:04:00.000 2
Sally 2010-07-22 01:00:00.000 9
Jane 2010-07-22 06:04:00.000 12
Alex 2010-07-22 05:54:00.000 EA
Vince 2010-07-22 07:59:00.000 30
Note that the building column has at least one non-numeric value. The range of buildings that report in changes over time, so I would prefer to avoid hard-coding of building values (a table that I can update would be fine).
Should I use a cursor or dynamic SQL to run a looping SELECT statement that checks for each building based on a control table listing each currently active building?
Any help would be appreciated.
Edit: spelling
You could create a stored procedure that checks for missing entries. The procedure could call raiserror to make the job fail. For example:
if OBJECT_ID('CheckBuildingEntries') is null
exec ('create procedure CheckBuildingEntries as select 1')
go
alter procedure CheckBuildingEntries(
#check_date datetime)
as
declare #missing_buildings int
select #missing_buildings = COUNT(*)
from Buildings as b
left join
YourTable as yt
on yt.Building = b.name
and dateadd(dd,0, datediff(dd,0,yt.RawDate)) =
dateadd(dd,0, datediff(dd,0,#check_date))
where yt.Building is null
if #missing_buildings > 0
begin
raiserror('OMG!', 16, 0)
end
go
An example scheduled job running at 4AM to check yesterday's entries:
declare #yesterday datetime
set #yesterday = dateadd(day, -1, GETDATE())
exec CheckBuildingEntries #yesterday
If an entry was missing, the job would fail. You could set it up to send you an email.
Test tables:
create table Buildings (id int identity, name varchar(50))
create table YourTable (Employee varchar(50), RawDate datetime,
Building varchar(50))
insert into Buildings (name)
select '2'
union all select '9'
union all select '12'
union all select 'EA'
union all select '30'
insert into YourTable (Employee, RawDate, Building)
select 'Bob', '2010-07-22 06:04:00.000', '2'
union all select 'Sally', '2010-07-22 01:00:00.000', '9'
union all select 'Jane', '2010-07-22 06:04:00.000', '12'
union all select 'Alex', '2010-07-22 05:54:00.000', 'EA'
union all select 'Vince', '2010-07-22 07:59:00.000', '30'
Recommendations:
Do use a control table for the buildings - you may find that one
already exists, if you use the Object
Explorer in SQL Server Management
Studio
Don't use a cursor or dynamic SQL to run a loop - use set based
commands instead, possibly something
like the following:
SELECT BCT.Building, COUNT(YDT.Building) Build
FROM dbo.BuildingControlTable BCT
LEFT JOIN dbo.YourDataTable YDT
ON BCT.Building = YDT.Building AND
CAST(FLOOR( CAST( GETDATE() AS FLOAT ) - 1 ) AS DATETIME ) =
CAST(FLOOR( CAST( YDT.RawDate AS FLOAT ) ) AS DATETIME )
GROUP BY BCT.Building