I try to use DISTINCT to avoid duplication of the data, but no work.
How to avoid the duplicate data?
Table 1
Employee code Deduction Voucher no Dec_Amount
001 999 50
001 888 20
002 777 100
Table 2
Employee code Payslip Voucher No Pay_Amount
001 111 100
002 222 200
The output should be:
Employee code Deduction Voucher no Dec_Amount Payslip Voucher No Pay_Amount
001 999 50 111 100
001 888 20
002 777 100 222 200
But i got the table like this.
Employee code Deduction Voucher no Dec_Amount Payslip Voucher No Pay_Amount
001 999 50 111 100
001 888 20 111 100
002 777 100 222 200
You cannot get those results with just a SQL query. It seems to me you need it in this format for display in a table/excel spreadsheet. If this is the case you would have to handle the "Hiding" of the particular entries with some other code. The reason is because the entries you want to hide are correctly associated with the 001 employee.
While I do agree this probably makes a lot more sense to do in your front end code, it is possible to do in SQL. Using a variable you get a function similar to SQL Server's ROW_NUMBER function and then only join on the first row per employee code.
See the sqlfiddle - http://sqlfiddle.com/#!2/47302/11
SELECT t1.`Employee code`,`Deduction Voucher no`,`Dec_Amount`,
COALESCE(`Payslip Voucher No`,'') as `Payslip Voucher No`,
COALESCE(CAST(`Pay_Amount` as char(10)),'') as `Pay_Amount`
FROM Table2 t2
RIGHT JOIN
(
SELECT #row_num := IF(#prev_value=`Employee code`,#row_num+1,1) AS RowNumber
,`Employee code`,`Deduction Voucher no`,`Dec_Amount`
,#prev_value := `Employee code`
FROM Table1,
(SELECT #row_num := 1) x,
(SELECT #prev_value := '') y
ORDER BY `Employee code`
) t1
ON t1.`Employee code`=t2.`Employee code` AND t1.RowNumber=1
To expand on #d.lanza38's answer, there is no way given for the DB to tell which row in table1 should get the data from table2. Remember that there is no order to the data in the database, so there is no inherent concept of "the first row with employee code 001".
A standard (inner) join will put them as you have shown - on both. Which is actually correct - your table structures say that for every payslip in table2, there can be many deductions. So if you want the data from both tables, the deductions have to have the matching payslip data attached.
You can't use DISTINCT to magically fix your data - you need to understand the data structures, and relate them correctly.
To get what is in your example (which may be wrong) try this SQL:
select
a.Employee_code,
Deduction_Voucher_no,
Dec_Amount,
Payslip_Voucher_No,
Pay_Amount
from
table1 as a
inner join table2 as b on a.employee_code = b.employee_code
where Deduction_Voucher_no = (
select max(Deduction_Voucher_no)
from table1 as c
where a.Employee_code = c.Employee_code)
UNION
select
a2.Employee_code,
Deduction_Voucher_no,
Dec_Amount,
null as Payslip_Voucher_No,
null as Pay_Amount
from
table1 as a2
inner join table2 as b2 on a2.employee_code = b2.employee_code
where Deduction_Voucher_no <> (
select max(Deduction_Voucher_no)
from table1 as c2
where a2.Employee_code = c2.Employee_code)
order by 1,2 desc
Note: untested, because I don't have your database, and don't even know which database engine you are using. If it complains about selecting nulls, replace with 0 or '' depending upon the data type.
UPDATE improved SQL and provided a fiddle: http://sqlfiddle.com/#!2/e7fc2/2
Related
I'm using the following query to create a view. It's currently only grabbing data from two different tables, subscriptions and subscriptionitems.
For each subscription, I want to grab the item data and output it in the column, the concat function is grabbing one row at the moment and outputting the data in the correct format.
The problem I have is that a subscription can have multiple items, so I need to grab each one and tie it to the correct subscription via the where statement.
How can I do that?
I've read about using UNION ALL, is that the right direction to go?
CREATE VIEW Sub_Products AS
(
SELECT
i.subscription_id as "Subscription ID",
concat('product_id:',i.product_id,'|quantity:',i.quantity,'|total:',(i.unit_price * i.quantity),'|meta:|tax:0;') as "Products"
FROM subscriptions s, subscriptionitems i, customerdata c
WHERE s.id = i.subscription_id
AND i.active = 1
);
So as an example of the output - any with the same subscription id should be combined and the products should be output in the same row.
So the subscription 217 should have in the products column "product_id:253|quantity:1|total:2.34|meta:|tax:0;product_id:252|quantity:1|total:2.43|meta:|tax:0;"
Sample data from the subscriptionitems table:
id
subscription_id
customer_id
product_id
quantity
active
unit_price
556
230
184
262
1
0
2.79
8100
230
184
262
1
1
2.79
555
230
184
260
1
0
2.52
This is my attempt:
CREATE VIEW Sub_Products AS
(
SELECT
i.subscription_id as "Subscription ID",
GROUP_CONCAT('product_id:',i.product_id,'|quantity:',i.quantity,'|total:',(i.unit_price * i.quantity),'|meta:|tax:0;') as "Products"
FROM subscriptions s, subscriptionitems i, customerdata c
WHERE s.id = i.subscription_id
AND i.active = 1
GROUP BY i.subscription_id
);
Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax.
If you did so, you would probably notice that there is no JOIN condition for customerdata. In fact, that table is not used at all. And neither is subscriptions.
I would suggest
SELECT i.subscription_id ,
GROUP_CONCAT('product_id:', i.product_id,
'|quantity:', i.quantity,
'|total:', (i.unit_price * i.quantity),
'|meta:|tax:0;'
) as Products
FROM subscriptionitems i
WHERE i.active = 1 ;
GROUP BY i.subscription_id;
Note that I fixed the column names so no escaping is needed either.
I have two tables with invoice detail and serial numbers.
Both tables have invoice number, but when I attempt to join using left or inner join the amount duplicates in each lines. I want to list down all the serials associated with my invoice # in table 1 without duplicating the amount each lines. I'm currently using MS Access.
Thanks for the help.
Table 1
Invoice# amount
001 500
Table 2
Invoice# serial
001 123
001 456
001 789
001 1011
001 1213
Desired Output:
Invoice# amount serial
001 500 123
456
789
1011
1213
My Current Query Output:
Query:
Select invoice.invoice,invoice.amount,tblmachine.serial
From tblmachine inner join invoice on tblmachine.invoice =invoice.invoice;
Use UNION ALL for 2 queries.
The 1st will return the 1st row that you need and the 2nd all the rest:
select i.[invoice#], i.amount, min(t.serial) as serial
from tblmachine as t inner join invoice as i
on t.[invoice#] = i.[invoice#]
where i.[invoice#] = '001'
group by i.[invoice#], i.amount
union all
select null, null, t.serial
from tblmachine as t
where t.[invoice#] = '001'
and t.serial > (select min(serial) from tblmachine where [invoice#] = t.[invoice#])
Results:
invoice# amount serial
001 500 123
456
789
1011
1213
Can't do that desired output in query for multiple invoices.
Build a report and set textbox HideDuplicates property to Yes.
I am trying to find the second max based on two different categories. I can use analtycal function or logic to get this. I have been trying to find this through a logic.
My question is I am trying to fetch the records of second most taken exam per country by unique students.
T1
Exam_ID Student_ID
123 553
123 457
345 563
567 765
678 543
678 543
987 123
678 123
T2
Exam_ID Exam_name Country_name
123 SAT USA
345 CAT USA
567 GRE USA
678 TOEFL UK
987 IELTS UK
222 CBAP UK
This is what I tried so far,
select count(distinct T1.Student_ID) count_user,
t2.Country_name,t2.Exam_name
from T1
join T2
on T1.Exam_ID = T2.Exam_ID
group by t2.Exam_name, t2.Country_name
By doing this I am able to get the unique student count based on each exam and country.
How can I get the second max no of exams taken by unique students based on the country?
I'm not sure I fully understand what you mean by your question.
Could you post the expected result along with what you are getting now?
In the mean time, I'm taking a guess that exam_id 678 in the UK (with 3 students) is the top result and 987 in the UK is the "second top result"???
If so, Row_number () might work for you. Bear in mind that row_number is usually an expensive operation in relational databases as it involves a redistribution and a sort. A similar function Rank () may be better for you depending upon how you want to handle ties. The syntax is similar, you could try both.
Try modifying your query as follows:
select count(distinct T1.student_id) count_user, Country_name, Exam_name,
row_number () over (partition by country_name order by count_user desc) as row_num
...
If that gives you the numbering you want, you can then restrict the output using the qualify clause i.e.
qualify row_num = 2
You may need to wrap the whole thing in a derived table as follows:
select count_user, country_name, exam_name,
row_number () over (partition by country_name order by count_user desc) as row_num
from (
select count(distinct T1.Student_ID) count_user,
t2.Country_name,t2.Exam_name,
from T1 join T2
on T1.Exam_ID = T2.Exam_ID
group by t2.Exam_name, t2.Country_name
) detail_recs
qualify row_num = 2
I have two tables, donaTypes and fullInfo.
fullInfo:
id funddesc giftamt giftdate
001 annual fund 50.00 2010-03-09
223 alumni fund 25.00 2009-03-06
334 capital exp 100.00 2011-09-27
... ... ... ...
donaTypes:
id donaType
1 annual fund
2 capital exp
3 alumni fund
I'm trying to match up where fullInfo.funddesc = donaTypes.donaType with the hope of inserting the donaTypes.id number into the fullInfo table. Here's my code but I just get a blank response (no error):
SELECT st1.funddesc, st2.donatype
FROM
(select t1.funddesc
from fullInfo as t1) st1
inner join
(select t2.donatype
from donatTypes as t2) st2
on trim(st1.funddesc) like trim(st2.donaType)
;
I also tried :
SELECT t1.funddesc, t2.donatype
FROM fullInfo as t1,
donatTypes as t2
where trim(t1.funddesc) = trim(t2.donatype);
Ideally, I'd like fullInfo to look like this:
fullInfo:
id funddesc giftamt giftdate
001 1 50.00 2010-03-09
223 3 25.00 2009-03-06
334 2 100.00 2011-09-27
... ... ... ...
Keep it a bit simpler til you get it debugged. You don't need the nested queries. And, LIKE is not really very good for joins, because it can be kind of promiscuous.
SELECT fi.funddesc, dt.donaType
FROM fullinfo fi
JOIN donatTypes dt on trim(fi.funddesc) = trim(dt.donaType)
You may also want to do this sort of thing on your two tables just to figure out what kind of stuff you actually have in your join columns.
SELECT COUNT(*), concat('>>>',TRIM(funddesc),'<<<')
FROM fullinfo
GROUP BY concat('>>>',TRIM(funddesc),'<<<')
USING VB6 AND MS-ACCESS 2003
So on…,
TABLE 1
EMPID DATE
101 22-07-2009
201 22-07-2009
501 22-07-2009
301 23-07-2009
401 23-07-2009
501 23-07-2009
101 24-07-2009
501 24-07-2009
So on…,
From the above table two tables I want to display all EMP ids for the date wise
Expected Output
EMPID DATE
101 22-07-2009
201 22-07-2009
301
401
501 22-07-2009
101
201
301 23-07-2009
401 23-07-2009
501 23-07-2009
101 24-07-2009
201
301
401
501 24-07-2009
So on…,
Need Query Help.
Haven't executed to verify for sure, but this should get you most of the way there:
SELECT
AllPossibleCardEvents.PersonId,
AllPossibleCardEvents.EmpName,
AllPossibleCardEvents.TitleCode,
AllPossibleCardEvents.TitleName,
AllPossibleCardEvents.CardEventDate,
ActualCardEvents.CardEventDate AS MatchingCardEventDate
FROM
(
(
SELECT
p.PersonId,
p.EmpName,
p.TitleCode,
p.TitleName,
AllDates.CardEventDate
FROM
(SELECT DISTINCT CardEventDate FROM T_Cardevent) AllDates,
T_Person p
) AllPossibleCardEvents
LEFT OUTER JOIN T_Cardevent ActualCardEvents ON
AllPossibleCardEvents.PersonId = Actual.PersonId AND
AllPossibleCardEvents.CardEventDate = Actual.CardEventDate
)
Where "MatchingCardEventDate" will be NULL for records that are NOT actual events. For actual events, the value of "MatchingCardEventDate" will be the valid date.
Hope this helps.
Without questioning your data model, to get the results you want you will need a third table (which I will call Dates) You need a Cross Join on Table 1 and Dates, which will give a result of all employees for all days. Then you need to Left Join to EmpID and Date.
The Left Join will include all of the results from the first join but only the matching rows from Table 2 will be populated. Access is funny in how it handles query structure, also it does not support the SQL-92 CROSS JOIN syntax, but it would look something like the below.
SELECT t1.EmpID, t2.Date
FROM (
SELECT t1.EmpID, d.Date
FROM [Table 1] AS t1,
Dates AS d
) AS DT1
LEFT OUTER JOIN [Table 2] AS t2
ON DT1.EmpID = t2.EmpID
AND DT1.Date = t2.Date
ORDER
BY DT1.Date, DT1.EmpID;