TSQL select and join issue - tsql

I have two tables, EMPL which is a historical employee table to track changes in an employee's tax rate and PAYROLL which is also a historical table filled with employee pay over a number of periods.
FROM EMPL, based upon the EMPL.effect_pd <= PAYROLL.payroll_pd, only one record should be joined from EMPL to PAYROLL.
Below are the two tables, query and result set. However, I only want 1 record for each employee per pay period, which matches the relevant employee record based upon the payroll_pd and effect_pd.
(Click image to enlarge)

first of all - welcome!
You wrote "...FROM EMPL, based upon the EMPL.effect_pd <= PAYROLL.payroll_pd ..." but you start your SQL with PAYROLL and not with EMPL.
Pls test this statement first:
SELECT
E.rec_id
,E.empl_id
,E.empl_name
,E.tax_rate
,E.effect_pd
,P.rec_id
,P.payroll_pd
,P.empl_id
,P.pd_pay
FROM
empl AS E
LEFT OUTER JOIN
payroll AS P
ON E.empl_id = P.empl_id
AND E.effect_pd < P.payroll_pd
After that you get 7 records witch are uniqe.
i think, thats it.
Best regards

After 3 days of messing around with the code, I finally arrived at the solution which is:
SELECT * FROM PAYROLL p
LEFT JOIN EMPL e on p.empl_id = e.empl_id
WHERE e.rec_id = ( SELECT TOP 1 c.rec_id
FROM EMPL c
WHERE c.empl_id = p.empl_id
AND p.payroll_pd >= c.effect_pd
ORDER BY c.effect_pd DESC );

Related

Return closest timestamp from Table B based on timestamp from Table A with matching Product IDs

Goal: Create a query to pull the closest cycle count event (Table C) for a product ID based on the inventory adjustments results sourced from another table (Table A).
All records from Table A will be used, but is not guaranteed to have a match in Table C.
The ID column will be present in both tables, but is not unique in either, so that pair of IDs and Timestamps together are needed for each table.
Current simplified SQL
SELECT
A.WHENOCCURRED,
A.LPID,
A.ITEM,
A.ADJQTY,
C.WHENOCCURRED,
C.LPID,
C.LOCATION,
C.ITEM,
C.QUANTITY,
C.ENTQUANTITY
FROM
A
LEFT JOIN
C
ON A.LPID = C.LPID
WHERE
A.facility = 'FACID'
AND A.WHENOCCURRED > '23-DEC-22'
AND A.ADJREASONABBREV = 'CYCLE COUNTS'
ORDER BY A.WHENOCCURRED DESC
;
This is currently pulling the first hit on C.WHENOCCURRED on the LPID matches. Want to see if there is a simpler JOIN solution before going in a direction that creates 2 temp tables based on WHENOCCURRED.
I have a functioning INDEX(MATCH(MIN()) solution in Excel but that requires exporting a couple system reports first and is extremely slow with X,XXX row tables.
If you are using Oracle 12 or later, you can use a LATERAL join and FETCH FIRST ROW ONLY:
SELECT A.WHENOCCURRED,
A.LPID,
A.ITEM,
A.ADJQTY,
C.WHENOCCURRED,
C.LPID,
C.LOCATION,
C.ITEM,
C.QUANTITY,
C.ENTQUANTITY
FROM A
LEFT OUTER JOIN LATERAL (
SELECT *
FROM C
WHERE A.LPID = C.LPID
AND A.whenoccurred <= c.whenoccurred
ORDER BY c.whenoccurred
FETCH FIRST ROW ONLY
) C
ON (1 = 1) -- The join condition is inside the lateral join
WHERE A.facility = 'FACID'
AND A.WHENOCCURRED > DATE '2022-12-23'
AND A.ADJREASONABBREV = 'CYCLE COUNTS'
ORDER BY A.WHENOCCURRED DESC;

Unexpected Results From Postgresql Query

I am trying to find a way to create a table where it shows each customer profile (71 in total) their top item bought per time frame (10 in total), what that item is, and the time frame that was most popular. Whenever I run this query it shows the top items for a time frame but it shows all the customers as null. I also need a way to display the customer name which is also accessed through the id_table. I'm lost so any direction would be greatly appreciated! I only have read permissions on this DB.
select distinct id_table.name as product_name, pb.recruitment_round, count(pb.purchased), st.cust_dbf_id as cust_profile
from product_bought pb
join id_table
on id_table.dbf_id = pb.dbf_id
left join shopper_table st
on st.cust_dbf_id = id_table.dbf_id
where pb.date >= '2022-01-01'
and pb.date <= '2022-01-05'
and pb.shopping_time = 4
group by id_table."name", pb.recruitment_round, pb.cust_dbf_id
order by count(pb.purchased) desc, pb.recruitment_round
limit 1;
Expected: a return of st.cust_dbf_id.
Received: Null values

Can I calculate the sum of a calculated field in the same query?

I need to tally the total number of characters entered by students for all posts in a given Moodle course (as well as the total number of posts per student). I started simple with a query that looks at just one student and one course at a time, and produces a new column with the character_length of the forum message. It works fine, but I have to tally the column manually and I'm only working with one student and course at a time. My query:
SELECT character_length(mdl_forum_posts.message) AS CHARS
FROM mdl_forum_posts, mdl_forum_discussions
WHERE mdl_forum_posts.userid = 1120
AND mdl_forum_posts.discussion = mdl_forum_discussions.id
AND mdl_forum_discussions.course = 181
Can I:
a) tally the CHARS column and just get the total for all posts in a single query
or
b) (even better) do this for a list of student/course combinations in one query?
Any information greatly appreciated. This table is postgres, though ultimately I have to generate this code in a query-builder that will work for other RDBMSs as well.
SELECT character_length(string_agg(mdl_forum_posts.message)) AS CHARS
FROM mdl_forum_posts, mdl_forum_discussions
WHERE mdl_forum_posts.userid = 1120
AND mdl_forum_posts.discussion = mdl_forum_discussions.id
AND mdl_forum_discussions.course = 181
GROUP BY mdl_forum_posts.message;
SELECT p.userid
,d.course
,SUM(character_length(p.message)) AS char_total
,COUNT(p.message) AS post_count
FROM mdl_forum_posts p
JOIN mdl_forum_discussions d ON (d.id = p.discussion)
GROUP BY p.userid, d.course
ORDER BY p.userid, d.course
;
select
d.id, p.user_id,
count(*) as total_posts,
sum(character_length(p.message)) as chars
from
mdl_forum_posts p
inner join
mdl_forum_discussions d on p.discussion = d.id
group by rollup (d.id, p.user_id)

Tableau - Calculating average where date is less than value from another data source

I am trying to calculate the average of a column in Tableau, except the problem is I am trying to use a single date value (based on filter) from another data source to only calculate the average where the exam date is <= the filtered date value from the other source.
Note: Parameters will not work for me here, since new date values are being added constantly to the set.
I have tried many different approaches, but the simplest was trying to use a calculated field that pulls in the filtered exam date from the other data source.
It successfully can pull the filtered date, but the formula does not work as expected. 2 versions of the calculation are below:
IF DATE(ATTR([Exam Date])) <= DATE(ATTR([Averages (Tableau Test Scores)].[Updated])) THEN AVG([Raw Score]) END
IF DATEDIFF('day', DATE(ATTR([Exam Date])), DATE(ATTR([Averages (Tableau Test Scores)].[Updated]))) > 1 THEN AVG([Raw Score]) END
Basically, I am looking for the equivalent of this in SQL Server:
SELECT AVG([Raw Score]) WHERE ExamDate <= (Filtered Exam Date)
Below a workbook that shows an example of what I am trying to accomplish. Currently it returns all blanks, likely due to the many-to-one comparison I am trying to use in my calculation.
Any feedback is greatly appreciated!
Tableau Test Exam Workbook
I was able to solve this by using Custom SQL to join the tables together and calculate the average based on my conditions, to get the column results I wanted.
Would still be great to have this ability directly in Tableau, but whatever gets the job done.
Edit:
SELECT
[AcademicYear]
,[Discipline]
--Get the number of student takers
,COUNT([Id]) AS [Students (N)]
--Get the average of the Raw Score
,CAST(AVG(RawScore) AS DECIMAL(10,2)) AS [School Mean]
--Get the number of failures based on an "adjusted score" column
,COUNT([AdjustedScore] < 70 THEN 1 END) AS [School Failures]
--This is the column used as the cutoff point for including scores
,[Average_Update].[Updated]
FROM [dbo].[Average] [Average]
FULL OUTER JOIN [dbo].[Average_Update] [Average_Update] ON ([Average_Update].[Id] = [Average].UpdateDateId)
--The meat of joining data for accurate calculations
FULL OUTER JOIN (
SELECT DISTINCT S.[Id], S.[LastName], S.[FirstName], S.[ExamDate], S.[RawScoreStandard], S.[RawScorePercent], S.[AdjustedScore], S.[Subject], P.[Id] AS PeriodId
FROM [StudentScore] S
FULL OUTER JOIN
(
--Get only the 1st attempt
SELECT DISTINCT [NBOMEId], S2.[Subject], MIN([ExamDate]) AS ExamDate
FROM [StudentScore] S2
GROUP BY [NBOMEId],S2.[Subject]
) B
ON S.[NBOMEId] = B.[NBOMEId] AND S.[Subject] = B.[Subject] AND S.[ExamDate] = B.[ExamDate]
--Group in "Exam Periods" based on the list of periods w/ start & end dates in another table.
FULL OUTER JOIN [ExamPeriod] P
ON S.[ExamDate] = P.PeriodStart AND S.[ExamDate] <= P.PeriodEnd
WHERE S.[Subject] = B.[Subject]
GROUP BY P.[Id], S.[Subject], S.[ExamDate], S.[RawScoreStandard], S.[RawScorePercent], S.[AdjustedScore], S.[NBOMEId], S.[NBOMELastName], S.[NBOMEFirstName], S.[SecondYrTake]) [StudentScore]
ON
([StudentScore].PeriodId = [Average_Update].ExamPeriodId
AND [StudentScore].Subject = [Average].Subject
AND [StudentScore].[ExamDate] <= [Average_Update].[Updated])
--End meat
--Joins to pull in relevant data for normalized tables
FULL OUTER JOIN [dbo].[Student] [Student] ON ([StudentScore].[NBOMEId] = [Student].[NBOMEId])
INNER JOIN [dbo].[ExamPeriod] [ExamPeriod] ON ([Average_Update].ExamPeriodId = [ExamPeriod].[Id])
INNER JOIN [dbo].[AcademicYear] [AcademicYear] ON ([ExamPeriod].[AcademicYearId] = [AcademicYear].[Id])
--This will pull only the latest update entry for every academic year.
WHERE [Updated] IN (
SELECT DISTINCT MAX([Updated]) AS MaxDate
FROM [Average_Update]
GROUP BY[ExamPeriodId])
GROUP BY [AcademicYear].[AcademicYearText], [Average].[Subject], [Average_Update].[Updated],
ORDER BY [AcademicYear].[AcademicYearText], [Average_Update].[Updated], [Average].[Subject]
I couldn't download your file to test with your data, but try reversing the order of taking the average ie
average(IF DATE(ATTR([Exam Date])) <= DATE(ATTR([Averages (Tableau Test Scores)].[Updated]) then [Raw Score]) END)
as written, I believe you'll be averaging the data before returning it from the if statement, whereas you want to return the data, then average it.

t sql query returns duplicate values

I know this is an often asked question, but I've tried to resolve this myself and could not.
I've got 2 tables to join and now it's returning a duplicate value from the right table.
select am.Journal
,am.EntryNumber
,am.PayInvoice
,am.PayDiscAllowed
,am.PayTaxAmtDisc
,am.PayGrossPayment
,tm.*
from CshJnlPay am right join
(select
Invoice
,SUM(NetSalesValue) as NetSalesValue
,SUM(DiscValue) as DiscValue
,SUM(TaxValue) as TaxValue
,SUM(QtyInvoiced) as QtyInvoiced
from Salesdetail
group by Invoice) tm
on am.PayInvoice = tm.Invoice
where Invoice = 'C90831'
If the query returns 2 rows with the same data from the right table then you have 2 rows in the left table with the same invoice number...
You should check the left table with this query
Select * from CshJnlPay where PayInvoice = 'C90831'
You should get two rows.