List records that are in a table and those that are not in the same table

Asked

Viewed 1,305 times

2

I have a points table and a users table. At points, I have an ID that references the users table user. What I need to do is return all users who have hit the point, along with those who haven’t hit the point. So I can see who hit and who didn’t hit point on any date.

The points table has the following data:

  • date Date type (date the user hit the point)
  • user (user id reference in User table)
  • inada01 TIME type (time the user entered)
  • out01 type TIME (time the user left)
  • entrada02 TIME type (time the user entered)
  • out02 type TIME (time the user left)

The user table has the following data: id, name

  • Something like this doesn’t solve? select * from users inner join pontos on pontos.user = user.id

  • @Diegof This way I can only see who hit, but I need to return, too, who did not hit the point on each date.

  • Then show the structure of your table, the question is not clear.

  • I changed the code to show the attributes.

  • If it’s to show all users, one users LEFT JOIN pontos must solve.

3 answers

1

I will assume that a user who has entered 01 or entered 02 on the selected date has clocked in.

DECLARE @DATA DATE;
SET @DATA = '2016-05-09';



select
    nome,
    CASE WHEN Picou > 0 then 'Sim' else 'Não' end 'Picou'
from (
    select
        u.nome,
        SUM(CASE WHEN DATE(d.entrada01) = @DATA OR
        DATE(d.entrada02) THEN 1 ELSE 0 END) 'Picou'
    from user u
    left join dados d on
        u.id = d.usuarioid
    group by
        u.nome
) t

EDIT:

DECLARE @DATA DATE;
SET @DATA = '2016-05-09';

select
    u.nome,
    d.*
from user u
left join (
    select
        d.*
    from dados d on
    where
        DATE(d.entrada01) = @DATA OR
        DATE(d.entrada02) = @DATA
) d on
    u.id = d.usuarioid
  • worked. However, I need to return all the attributes I put (datePonto, u.nome, inada01, saida01, inada02, saida02) because, at first, I have to return all the dates. I modified your solution to return these attributes and my return was like this: of the 5 users I have in my bank, only one hit the point on the date specified by you. The other 4 appeared with attributes filled by values of other tuples. For example, a user appeared with the date of a day when he hit the point. I don’t know if I could understand.

  • 1

    Could you check if EDIT is what you are trying? Otherwise I suggest you include sample data and expected result.

  • still not what I expect. Let’s try as you suggested. Suppose I have 5 users in my User table. However, only 2 users registered their point. Soon, on the date "09-05-2016" will have only two registered users. My goal is to list all points, but let’s filter only by the date "09-05-2016". So, when selecting this date, I want to see the users who hit the point (in case only 2) plus the other 3 who didn’t. So, I will know who hit the point and who stopped hitting. I could understand more or less?

  • The query below "EDIT" has to return this. All users and users who have bitten the point will have associated data, others will not.

1

In the Caffé solution, it was only necessary to include a clause in the Where data is null:

    select 
    user.id, user.nome, ponto.data, ponto.entrada01, 
    ponto.saida01, ponto.entrada02, ponto.saida02
    (case when ponto.data is not null then 'sim' else 'não') as bateu_ponto
from user left join ponto on ponto.usuarioId = user.id
where (data is null or (data between data1 and data2))
group by user.id, user.nome, ponto.data, ponto.entrada01, 
ponto.saida01, ponto.entrada02, ponto.saida02, bateu_ponto 

Users who have not hit the point do not have the date, for this reason, you also need to consider that the date is null or in the range you inform to users who have point.

======================CORRECT SOLUTION=====================

The above solution does not answer. If the user has a point at a date other than the one reported in Where, that is, it does not meet the Where clauses because it is not null and is different from the filter date.

The correct solution was to create a sub query only with the points of the day you want to query, with this table I made a left Join with user, now all users are being returned even if there are points for other dates. Follow the new query:

select user.id, user.name, ponto.dataPonto, 
       ponto.entrada01, ponto.saida01, 
       ponto.entrada02, ponto.saida02,
    case when (ponto.dataPonto is not null) then 'sim' else 'não' end as bateu_ponto

from user left join

     (select * 

      from pontospordia p 

      where p.dataPonto between '2016-05-07' and '2016-05-10 23:59:59') ponto on ponto.usuarioId = user.id
group by user.id, 
         user.name, 
         ponto.dataPonto, 
         ponto.entrada01, 
         ponto.saida01, 
         ponto.entrada02, 
         ponto.saida02 

I hope I’ve helped.

  • @Caffé, I did a test excluding the last Sert of the table pontospordia, since it was equal to the penultimate. In this case, only one user would have hit the spot on the date '2016-05-10'. Thus, it should return 4 null users, correct? Look: [link]http://sqlfiddle.com/#! 9/cdcdf5/2

  • @Caffé Marcelo, I think I understand what you want based on your last comment. Once informed a period, you want for each day of that period all users to be displayed, in which case we would have to think of a third solution. That’s it?

  • Yes, @Caffé. Exactly that. I want to see every user for every day.

  • Something wrong with having to create a precedent?

  • The problem is that when an employee hits the point on a date, he does not appear as a defaulter on the other date he did not hit.

0

It works:

select 
    user.id, user.name, ponto.dataPonto, ponto.entrada01, 
    ponto.saida01, ponto.entrada02, ponto.saida02,
    case when ponto.dataPonto is not null then 'sim' else 'não' end bateu_ponto
from 
    user left join pontospordia ponto on ponto.usuarioId = user.id
where 
    (dataPonto between '2016-05-07' and '2016-05-10')
    or dataPonto is null
group by 
    user.id, user.name, ponto.dataPonto, ponto.entrada01, 
    ponto.saida01, ponto.entrada02, ponto.saida02, bateu_ponto

Above is my original query plus OR of @Developer.

See it working in your sql fiddle: http://sqlfiddle.com/#! 9/332356/60.

The only thing is that searching for more than one date and showing the query date doesn’t help much to know when a user did not hit point, because if he did not hit he will not have a corresponding record in the beat table, so that will not show the date to him.

The solution is to query for a single date and display in the application the date used for the query instead of trying to get this date from the query result.

  • I tested your solution here, but it only shows users who have tapped the point. Users who have not tapped do not appear.

  • left Join causes all users to be returned, even if there is no point. The query does not seem wrong. Replaces Where by date is null or (date between data1 and data2) . The problem is in lines that have no date, you need to include the data is null.

  • @Developer, I did as you said, I only exchanged the data between... for a fixed date. But of the 5 users I have, only 3 were returned

  • @Marceloaugusto I edited the answer with my definitive query.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.