Query and Report Puzzle

Sort:
You are not authorized to post a reply.
Author
Messages
DavidBrianCampbell
Basic Member
Posts: 13
Basic Member
    Thanks in advance for any clues!

    I am from scratch (not DME due to using ODBC) writing a query in Crystal Reports. Below I have 2 tables (Employee & PRDISTRIB). What this is to report is payroll deductions by deduction. So within PRDISTRIB (and there might be a better Lawson table) I have a record for each single deduction (e.g. Check #502 for Mary Brown will have maybe 6 records or more, $10 Dental, $25 Health, $5 Uniform, etc.). So with this query and my corresponding report I get the employee name, number, position, etc. for each deduction. What I would really like is one listing of the Employee (with number, position) on a row with that row also having the six deductions. Also in the Employee table I have Employee.Department, which gives the number, but I need to pick up the Department name from the DEPTCODE table. So I need to do another join and the syntax is puzzling me. Any help would be great!


    SELECT EMPLOYEE.EMPLOYEE, EMPLOYEE.LAST_NAME,
    EMPLOYEE.FIRST_NAME, PRDISTRIB.EMPLOYEE, PRDISTRIB.POSITION, PRDISTRIB.Ded_Code, PRDISTRIB.CHECK_ID, PRDISTRIB.DIST_AMT, PRDISTRIB.DED_CODE, EMPLOYEE.DEPARTMENT, EMPLOYEE.JOB_CODE, EMPLOYEE.POSITION, EMPLOYEE.JOB_CODE, PRDISTRIB.PER_END_DATE,
    trim(last_name) || ', ' || trim(first_name) || ' ' ||
    case when trim(middle_init) is null then trim(middle_init) else trim(middle_init) || '.' end
    FROM PRDISTRIB PRDISTRIB INNER JOIN EMPLOYEE
    EMPLOYEE ON (PRDISTRIB.COMPANY=EMPLOYEE.COMPANY) AND (PRDISTRIB.EMPLOYEE=EMPLOYEE.EMPLOYEE)
    John Henley
    Senior Member
    Posts: 3348
    Senior Member
      Hi Brian,
      You have two easy options.
      1) Within Crystal, you would create this as a 'crosstab' report, which "pivots" on the deduction code to put the values into columns/buckets.
      2) You can also use 'CASE' statements within your SQL to create a "poor man's" crosstab:
      ... case when ded_code = 'HEAL' then dist_amt else 0 end as health_amt ...
      You would then summarize by employee and suppress the details

      BTW, you might find that it's easier to create this report from PAYDEDUCTN instead of PRDISTRIB.
      Thanks for using the LawsonGuru.com forums!
      John
      k-rock
      Veteran Member
      Posts: 142
      Veteran Member
        In these cases, I find that loading a temp table is the easiest. Do your PRDISTRIB pull into a temp table. Join that table to DEPTARTMENT, update the dept name on your temp table, then pull a crosstab query from the temp table. This should also increase performance because you won't be doing a crosstab off of Lawson tables.
        Chris Martin
        Veteran Member
        Posts: 277
        Veteran Member
          The relationship between EMPLOYEE and DEPTCODE is on company/process_level/department.
          DavidBrianCampbell
          Basic Member
          Posts: 13
          Basic Member
            I'm manually coding this due to using ODBC. So I've got to refresh my memory for writing cross-tab queries. Basically what I want to do is search for Employees that meet a certain criteria and list their deductions in the following format, so I'm looking at some rather complex SQL, maybe. The first line is a header and each person listed is a detail "row" resulting from a join, to be determined. Each deduction amount and its deduction code are individual records (coming from the ONETMDED table), that is each person has anywhere from 0-6 records forming their row in the detail.


            DED CODE DED AMT DED CODE DED AMT DED CODE DED AMT

            Mary Brown HFGD 15.25 HFTS 44.10 JFFC 53.10
            401K 80.11 SSHG 16.16 KLL1 90.00

            Steve Cash HFGD 19.20 HFTS 18.44 JFFC 55.54
            401K 28.74 SSHG 59.15 KLL1 75.11

            Pat Lomax HFGD 22.64 HFTS 50.50 JFFC 45.66
            401K 30.69 KLL1 75.41
            John Henley
            Senior Member
            Posts: 3348
            Senior Member
              There are a few different ways to tackle this.

              One is to use nested subqueries, where each column is a separate SELECT query, JOINed to a larger SELECT query...like this (in this example, I'm using PAYDEDUCTN, you'd be using ONETMDED and could leave out the PAYMASTR fields...):
              SELECT
              PAY.COMPANY AS COMPANY,
              PAY.EMPLOYEE AS EMPLOYEE,
              PAY.PROCESS_LEVEL AS PROCESS_LEVEL,
              PAY.DEPARTMENT AS DEPARTMENT,
              PROD.EMPLOYEE.EMP_STATUS AS EMP_STATUS,
              PROD.EMPLOYEE.JOB_CODE AS JOB_CODE,
              PROD.EMPLOYEE.SALARY_CLASS AS SALARY_CLASS,
              CHAR(PAY.CHECK_DATE,USA) AS CHECK_DATE,
              CHAR(PAY.PER_END_DATE,USA) AS PER_END_DATE,
              PAY.GROSS_PAY AS GROSS_PAY,
              HOURS.HOURS_WORKED,
              BONUS_PAY.BONUS_PAY,
              OTHER_PAY.OTHER_PAY,
              TCFU_DED.DED_AMT AS ER_FUTA_AMT,
              TCMC_DED.DED_AMT AS ER_MEDICARE_AMT,
              TCSS_DED.DED_AMT AS ER_SOCSEC_AMT,
              SUI.DED_AMT AS ER_SUI_AMT
              FROM
              PROD.PAYMASTR PAY
              LEFT OUTER JOIN PROD.EMPLOYEE
              ON ( PAY.COMPANY = PROD.EMPLOYEE.COMPANY
              AND PAY.EMPLOYEE = PROD.EMPLOYEE.EMPLOYEE )
              LEFT OUTER JOIN
              ( SELECT COMPANY,EMPLOYEE,CHECK_ID, SUM(WAGE_AMOUNT) AS BONUS_PAY FROM PROD.PRTIME
              WHERE PAY_SUM_GRP IN ('ABN','CBN','OBN','QBN','RBN','SBN','SBO','ZBN')
              GROUP BY COMPANY,EMPLOYEE,CHECK_ID) BONUS_PAY
              ON ( PAY.COMPANY = BONUS_PAY.COMPANY
              AND PAY.EMPLOYEE = BONUS_PAY.EMPLOYEE
              AND PAY.CHECK_ID = BONUS_PAY.CHECK_ID )
              LEFT OUTER JOIN
              ( SELECT COMPANY,EMPLOYEE,CHECK_ID, SUM(WAGE_AMOUNT) AS OTHER_PAY FROM PROD.PRTIME
              WHERE PAY_SUM_GRP IN ('AUT','OEA','GIF','NSO','QME','REL','SEV','TAX','ZNS','ZRL','ZTF')
              GROUP BY COMPANY,EMPLOYEE,CHECK_ID) OTHER_PAY
              ON ( PAY.COMPANY = OTHER_PAY.COMPANY
              AND PAY.EMPLOYEE = OTHER_PAY.EMPLOYEE
              AND PAY.CHECK_ID = OTHER_PAY.CHECK_ID )
              LEFT OUTER JOIN
              ( SELECT COMPANY,EMPLOYEE,CHECK_ID, SUM(R_HOURS) AS HOURS_WORKED FROM PROD.PRTIME
              GROUP BY COMPANY,EMPLOYEE,CHECK_ID) HOURS
              ON ( PAY.COMPANY = HOURS.COMPANY
              AND PAY.EMPLOYEE = HOURS.EMPLOYEE
              AND PAY.CHECK_ID = HOURS.CHECK_ID )
              LEFT OUTER JOIN
              ( SELECT COMPANY,EMPLOYEE,CHECK_ID, SUM(DED_AMT) AS DED_AMT FROM PROD.PAYDEDUCTN
              WHERE DED_CODE = 'TCMC'
              GROUP BY COMPANY,EMPLOYEE,CHECK_ID,DED_CODE) TCMC_DED
              ON ( PAY.COMPANY = TCMC_DED.COMPANY
              AND PAY.EMPLOYEE = TCMC_DED.EMPLOYEE
              AND PAY.CHECK_ID = TCMC_DED.CHECK_ID)
              LEFT OUTER JOIN
              ( SELECT COMPANY,EMPLOYEE,CHECK_ID,SUM(DED_AMT) AS DED_AMT FROM PROD.PAYDEDUCTN
              WHERE DED_CODE = 'TCSS'
              GROUP BY COMPANY,EMPLOYEE,CHECK_ID,DED_CODE) TCSS_DED
              ON ( PAY.COMPANY = TCSS_DED.COMPANY
              AND PAY.EMPLOYEE = TCSS_DED.EMPLOYEE
              AND PAY.CHECK_ID = TCSS_DED.CHECK_ID )
              LEFT OUTER JOIN
              ( SELECT COMPANY,EMPLOYEE,CHECK_ID,SUM(DED_AMT) AS DED_AMT FROM PROD.PAYDEDUCTN
              WHERE DED_CODE = 'TCFU'
              GROUP BY COMPANY,EMPLOYEE,CHECK_ID) TCFU_DED
              ON ( PAY.COMPANY = TCFU_DED.COMPANY
              AND PAY.EMPLOYEE = TCFU_DED.EMPLOYEE
              AND PAY.CHECK_ID = TCFU_DED.CHECK_ID )
              LEFT OUTER JOIN
              ( SELECT SUI.COMPANY,SUI.EMPLOYEE,SUI.CHECK_ID,SUM(DED_AMT) AS DED_AMT FROM PROD.PAYDEDUCTN SUI
              LEFT OUTER JOIN PROD.DEDCODE DED
              ON ( SUI.COMPANY = DED.COMPANY
              AND SUI.DED_CODE = DED.DED_CODE )
              WHERE DED.CALC_TYPE = 'T'
              AND DED.ADJUST_PAY = 'C'
              AND DED.TAX_CATEGORY = 10
              GROUP BY SUI.COMPANY,SUI.EMPLOYEE,SUI.CHECK_ID) SUI
              ON ( PAY.COMPANY = SUI.COMPANY
              AND PAY.EMPLOYEE = SUI.EMPLOYEE
              AND PAY.CHECK_ID = SUI.CHECK_ID )
              WHERE
              (
              ( PAY.STATUS = 9 )
              )
              ORDER BY
              COMPANY,
              EMPLOYEE,
              CHECK_DATE
              Thanks for using the LawsonGuru.com forums!
              John
              John Henley
              Senior Member
              Posts: 3348
              Senior Member
                Another way to do it is to use CASE statements to populate the columns (this is probably more efficient) but harder to read...

                SELECT EMPLOYEE,
                SUM(CASE WHEN DED_CODE = 'DED1' THEN DED_AMT ELSE 0 END) AS DED1_AMT,
                SUM(CASE WHEN DED_CODE = 'DED2' THEN DED_AMT ELSE 0 END) AS DED2_AMT
                FROM lawson.ONETMDED
                GROUP BY EMPLOYEE
                HAVING
                SUM(CASE WHEN DED_CODE = 'DED1' THEN DED_AMT ELSE 0 END) <> 0
                OR
                SUM(CASE WHEN DED_CODE = 'DED2' THEN DED_AMT ELSE 0 END) <> 0
                Thanks for using the LawsonGuru.com forums!
                John
                DavidBrianCampbell
                Basic Member
                Posts: 13
                Basic Member
                  I chose to keep it simple for now and just do "case when DED_CODE ='FSAH' then DED_AMT AS FSAH" to create a new field that I can place anywhere on the report, but I either get "FROM not in expected place" or "Missing Operator" errors.

                  SELECT
                  EMPLOYEE.EMPLOYEE,
                  EMPLOYEE.FICA_NBR,
                  EMPLOYEE.LAST_NAME,
                  EMPLOYEE.ADDR1,
                  EMPLOYEE.CITY,
                  EMPLOYEE.ADDR2,
                  EMPLOYEE.DEPARTMENT,
                  EMPLOYEE.TERM_DATE,
                  substr(DEPARTMENT,4,2),
                  EMPLOYEE.ZIP,
                  trim(employee.city) || ', ' || trim(employee.state) || ' ' || trim(employee.zip) as city_st_zip,
                  EMPLOYEE.STATE,
                  EMPLOYEE.PROCESS_LEVEL,
                  EMPLOYEE.FIRST_NAME,
                  trim(last_name) || ', ' || trim(first_name) || ' ' ||
                  case when trim(middle_init) is null
                  then trim(middle_init)
                  else trim(middle_init) || '.' end,
                  ONETMDED.EMPLOYEE,
                  ONETMDED.DED_CODE,
                  ONETMDED.DED_AMT,
                  case when DED_CODE ='FSAH' then DED_AMT AS FSAH
                  FROM EMPLOYEE EMPLOYEE INNER
                  JOIN ONETMDED ONETMDED ON EMPLOYEE.EMPLOYEE = ONETMDED.EMPLOYEE
                  WHERE ONETMDED.RECORD_TYPE ='A'
                  John Henley
                  Senior Member
                  Posts: 3348
                  Senior Member
                    You need to complete the CASE statement (you need the ELSE and END) for FSAH:
                    case when DED_CODE ='FSAH' then DED_AMT ELSE 0 END AS FSAH
                    Thanks for using the LawsonGuru.com forums!
                    John
                    Chris Martin
                    Veteran Member
                    Posts: 277
                    Veteran Member
                      Your case statement is incomplete. Look again at John's sample code (missing "else" and "end").
                      You are not authorized to post a reply.